mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-10-12 02:22:55 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae98159130 | ||
|
|
3a9e36c52b | ||
|
|
cb43c03712 | ||
|
|
65a0f15f69 | ||
|
|
98b77d32cc | ||
|
|
86a3569ccb | ||
|
|
17fca351d3 | ||
|
|
2614e7bec1 | ||
|
|
832c6e806f | ||
|
|
7b334b0808 | ||
|
|
aa9151785e | ||
|
|
6bdef1b7da | ||
|
|
8b4367d354 | ||
|
|
0a9d69a7d0 | ||
|
|
a4b60dc00f | ||
|
|
f91ae32284 | ||
|
|
53fc9d6720 | ||
|
|
0b31568306 | ||
|
|
e9407cf791 | ||
|
|
0175acd028 | ||
|
|
733a32de32 | ||
|
|
1b863ecf93 | ||
|
|
ec06037335 | ||
|
|
0cdb62a1b5 | ||
|
|
99454198b8 | ||
|
|
dd6287ace8 | ||
|
|
786460e3b4 | ||
|
|
419cf979f1 | ||
|
|
30be875304 | ||
|
|
7d011bc811 | ||
|
|
b2c4a3b247 | ||
|
|
9d9592a69b | ||
|
|
cb42294a7e | ||
|
|
146762c109 | ||
|
|
494b9d1586 | ||
|
|
2e95fdb52d | ||
|
|
46736cac7b | ||
|
|
041213f22d | ||
|
|
8ca45c5678 | ||
|
|
c6eec8db97 | ||
|
|
98fdc493f4 | ||
|
|
91372bff87 | ||
|
|
7fb9db42a7 | ||
|
|
82382957f9 | ||
|
|
f034122bd0 | ||
|
|
0df2456f34 | ||
|
|
78fdb27a0b | ||
|
|
350baf0a0a | ||
|
|
9886b646eb | ||
|
|
c5197b99a0 | ||
|
|
cc313280af | ||
|
|
f06ff42c58 | ||
|
|
4bc1cf4518 | ||
|
|
0e65043c84 | ||
|
|
d7d565415a | ||
|
|
0986ec8948 | ||
|
|
50bced511f | ||
|
|
e275e8c0b0 | ||
|
|
77dea38ac1 | ||
|
|
7dc2ec5fd8 | ||
|
|
4bf2e3b139 | ||
|
|
8114c14755 | ||
|
|
ec8cf6aadc | ||
|
|
d326965966 | ||
|
|
030df0353d | ||
|
|
5038d7a70a | ||
|
|
f0b8fbb7fd | ||
|
|
5810c2b199 | ||
|
|
77f0b5dfa8 | ||
|
|
b0ea74dc63 | ||
|
|
0c07c8942c | ||
|
|
7d1bdb35ca | ||
|
|
e823889819 | ||
|
|
680aedaefc | ||
|
|
afdca09ced | ||
|
|
ac89ee71c3 | ||
|
|
af7c8cff92 | ||
|
|
26d4dec5fb | ||
|
|
cf31d12528 | ||
|
|
b4c730f8c0 | ||
|
|
fba1720b31 | ||
|
|
9fad72f28b | ||
|
|
1782bf8e64 | ||
|
|
2d59a10515 | ||
|
|
21a25c4f00 | ||
|
|
6b5c16c22c | ||
|
|
2c6621c26a | ||
|
|
f0500b1d2f | ||
|
|
6a033bb58c | ||
|
|
2fa4b22645 | ||
|
|
229d3a7dd0 | ||
|
|
b965e5bf1c | ||
|
|
3bd74c5351 | ||
|
|
55624ec1a2 | ||
|
|
6885afe8c3 | ||
|
|
acc1277246 | ||
|
|
935cb9c8cb | ||
|
|
17a4ddad63 | ||
|
|
5264671f5b | ||
|
|
b4ebbae354 | ||
|
|
510197c39e | ||
|
|
b6a4bd91fe | ||
|
|
83b82a5e98 | ||
|
|
0b1efc0759 | ||
|
|
2b506d744d | ||
|
|
79d08906a4 | ||
|
|
d27b33e26c | ||
|
|
73d86f0fdd | ||
|
|
6327063bd0 | ||
|
|
69fd900108 | ||
|
|
f9d01f682b | ||
|
|
d7d3db415b | ||
|
|
608f141f52 | ||
|
|
31850e4544 | ||
|
|
de9f23939f | ||
|
|
154ed2c4e2 | ||
|
|
89dfe4e1ac | ||
|
|
b41b07ddd8 | ||
|
|
e36fc02282 | ||
|
|
49b41c1eca | ||
|
|
4cd9fdb7df | ||
|
|
5aab2d8fb5 | ||
|
|
210b65c02d | ||
|
|
7a2ac23f0b | ||
|
|
e435fb2e9e | ||
|
|
6892c94595 | ||
|
|
831c960216 | ||
|
|
43af2a4aee | ||
|
|
190819e85d | ||
|
|
1de6996c26 | ||
|
|
304f2ed308 | ||
|
|
148b35da4f | ||
|
|
3865b3a398 | ||
|
|
d6bcbbae1d | ||
|
|
04b3aefc5d | ||
|
|
a5f8cae599 | ||
|
|
29c3037512 | ||
|
|
d0d7d3a205 | ||
|
|
7ce36ea1b6 | ||
|
|
6f97f4796b | ||
|
|
39fe96009f | ||
|
|
b475a38895 | ||
|
|
42de887b05 | ||
|
|
28576bf08e | ||
|
|
c395958dff | ||
|
|
798b539eec | ||
|
|
70cf8edc75 | ||
|
|
a81ea88eb0 | ||
|
|
023dda26fc | ||
|
|
3e76895155 | ||
|
|
2c1bd7f034 | ||
|
|
f7cae68378 | ||
|
|
f6ff1a115a | ||
|
|
32ee586e2a | ||
|
|
b9e5655e3c | ||
|
|
6623c3f877 | ||
|
|
30a4173249 | ||
|
|
dbbe4c6ddd | ||
|
|
633e4dfe48 | ||
|
|
5e8b105677 | ||
|
|
414dd96bbd | ||
|
|
e857c2a88a | ||
|
|
e7aaea2b8e | ||
|
|
63d7cd607e | ||
|
|
d886b08dd9 | ||
|
|
72f3185ae7 | ||
|
|
03be9f9b65 | ||
|
|
d9d0865c13 | ||
|
|
e3f54bc226 | ||
|
|
9662f4a56a | ||
|
|
fea5cc8579 | ||
|
|
94091cd0e9 | ||
|
|
cc9f4b6102 | ||
|
|
cd7c99c752 | ||
|
|
75478c1181 | ||
|
|
ad0ca69579 | ||
|
|
2d801b7122 | ||
|
|
1e07269fe3 | ||
|
|
3b74e99576 | ||
|
|
439fff684e | ||
|
|
72cf06119c | ||
|
|
808068d70a | ||
|
|
f09072b2b6 | ||
|
|
be9381abc5 | ||
|
|
5d09f7b85f | ||
|
|
8bbfee7591 | ||
|
|
be26392057 | ||
|
|
263730f4ee | ||
|
|
5d7e1782d9 | ||
|
|
e27f590c2c | ||
|
|
7afe655561 | ||
|
|
3bf08290a4 | ||
|
|
34c2172391 | ||
|
|
48044f7a46 | ||
|
|
04e666182f | ||
|
|
c797129956 | ||
|
|
6928dae956 | ||
|
|
6db3bcbb51 | ||
|
|
d7f0b3566d | ||
|
|
0c67a90cc0 | ||
|
|
f06e498fb0 | ||
|
|
ad612bf9e4 | ||
|
|
9dd5cd8eb6 | ||
|
|
5ed3cdc819 | ||
|
|
e07c92bce5 | ||
|
|
0c5965c7b8 | ||
|
|
aa21550712 | ||
|
|
66061e8c5f | ||
|
|
c4b74c2e01 | ||
|
|
55b23e78ee | ||
|
|
a9526bda92 | ||
|
|
0901da3f83 | ||
|
|
8004652f7b | ||
|
|
c9b410c97f | ||
|
|
814d710320 | ||
|
|
38fcc5a35a | ||
|
|
674d516f3e | ||
|
|
8ceb4907a5 | ||
|
|
ce3749622a | ||
|
|
bcfae99701 | ||
|
|
44c1c2c6f0 | ||
|
|
ac08db82b2 | ||
|
|
305bfd9d30 | ||
|
|
f9aaec7b4a |
@@ -33,7 +33,7 @@ To get a list of all options and switches use:
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
You can find a sample run [here](https://gist.github.com/stamparm/5335217).
|
You can find a sample run [here](https://asciinema.org/a/46601).
|
||||||
To get an overview of sqlmap capabilities, list of supported features and description of all options and switches, along with examples, you are advised to consult the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki).
|
To get an overview of sqlmap capabilities, list of supported features and description of all options and switches, along with examples, you are advised to consult the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki).
|
||||||
|
|
||||||
Links
|
Links
|
||||||
@@ -59,6 +59,7 @@ Translations
|
|||||||
* [Croatian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md)
|
* [Croatian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md)
|
||||||
* [Greek](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md)
|
* [Greek](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md)
|
||||||
* [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md)
|
* [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md)
|
||||||
|
* [Japanese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md)
|
||||||
* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md)
|
* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md)
|
||||||
* [Spanish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md)
|
* [Spanish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md)
|
||||||
* [Turkish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md)
|
* [Turkish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ Para obtener una lista de todas las opciones:
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
Se puede encontrar una muestra de su funcionamiento [aquí](https://gist.github.com/stamparm/5335217).
|
Se puede encontrar una muestra de su funcionamiento [aquí](https://asciinema.org/a/46601).
|
||||||
Para obtener una visión general de las capacidades de sqlmap, así como un listado funciones soportadas y descripción de todas las opciones y modificadores, junto con ejemplos, se recomienda consultar el [manual de usuario](https://github.com/sqlmapproject/sqlmap/wiki).
|
Para obtener una visión general de las capacidades de sqlmap, así como un listado funciones soportadas y descripción de todas las opciones y modificadores, junto con ejemplos, se recomienda consultar el [manual de usuario](https://github.com/sqlmapproject/sqlmap/wiki).
|
||||||
|
|
||||||
Enlaces
|
Enlaces
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
Μπορείτε να δείτε ένα δείγμα λειτουργίας του προγράμματος [εδώ](https://gist.github.com/stamparm/5335217).
|
Μπορείτε να δείτε ένα δείγμα λειτουργίας του προγράμματος [εδώ](https://asciinema.org/a/46601).
|
||||||
Για μια γενικότερη άποψη των δυνατοτήτων του sqlmap, μια λίστα των υποστηριζόμενων χαρακτηριστικών και περιγραφή για όλες τις επιλογές, μαζί με παραδείγματα, καλείστε να συμβουλευτείτε το [εγχειρίδιο χρήστη](https://github.com/sqlmapproject/sqlmap/wiki).
|
Για μια γενικότερη άποψη των δυνατοτήτων του sqlmap, μια λίστα των υποστηριζόμενων χαρακτηριστικών και περιγραφή για όλες τις επιλογές, μαζί με παραδείγματα, καλείστε να συμβουλευτείτε το [εγχειρίδιο χρήστη](https://github.com/sqlmapproject/sqlmap/wiki).
|
||||||
|
|
||||||
Σύνδεσμοι
|
Σύνδεσμοι
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ Kako biste dobili listu svih opcija i prekidača koristite:
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
Možete pronaći primjer izvršavanja [ovdje](https://gist.github.com/stamparm/5335217).
|
Možete pronaći primjer izvršavanja [ovdje](https://asciinema.org/a/46601).
|
||||||
Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih značajki te opis svih opcija i prekidača, zajedno s primjerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki).
|
Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih značajki te opis svih opcija i prekidača, zajedno s primjerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki).
|
||||||
|
|
||||||
Poveznice
|
Poveznice
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Untuk mendapatkan daftar opsi lanjut gunakan:
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
Anda dapat mendapatkan contoh penggunaan [di sini](https://gist.github.com/stamparm/5335217).
|
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 [manual pengguna](https://github.com/sqlmapproject/sqlmap/wiki).
|
Untuk mendapatkan gambaran singkat kemampuan sqlmap, daftar fitur yang didukung, deskripsi dari semua opsi, berikut dengan contohnya, Anda disarankan untuk membaca [manual pengguna](https://github.com/sqlmapproject/sqlmap/wiki).
|
||||||
|
|
||||||
Tautan
|
Tautan
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# sqlmap
|
||||||
|
|
||||||
|
[](https://api.travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/doc/COPYING) [](https://twitter.com/sqlmap)
|
||||||
|
|
||||||
|
sqlmapはオープンソースのペネトレーションテスティングツールです。SQLインジェクションの脆弱性の検出、活用、そしてデータベースサーバ奪取のプロセスを自動化します。
|
||||||
|
強力な検出エンジン、ペネトレーションテスターのための多くのニッチ機能、持続的なデータベースのフィンガープリンティングから、データベースのデータ取得やアウトオブバンド接続を介したオペレーティング・システム上でのコマンド実行、ファイルシステムへのアクセスなどの広範囲に及ぶスイッチを提供します。
|
||||||
|
|
||||||
|
スクリーンショット
|
||||||
|
----
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
wikiに載っているいくつかの機能のデモをスクリーンショットで見ることができます。 [スクリーンショット集](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots)
|
||||||
|
|
||||||
|
インストール
|
||||||
|
----
|
||||||
|
|
||||||
|
最新のtarballを [こちら](https://github.com/sqlmapproject/sqlmap/tarball/master) から、最新のzipballを [こちら](https://github.com/sqlmapproject/sqlmap/zipball/master) からダウンロードできます。
|
||||||
|
|
||||||
|
[Git](https://github.com/sqlmapproject/sqlmap) レポジトリをクローンして、sqlmapをダウンロードすることも可能です。:
|
||||||
|
|
||||||
|
git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
|
||||||
|
|
||||||
|
sqlmapは、 [Python](http://www.python.org/download/) バージョン **2.6.x** または **2.7.x** がインストールされていれば、全てのプラットフォームですぐに使用できます。
|
||||||
|
|
||||||
|
使用法
|
||||||
|
----
|
||||||
|
|
||||||
|
基本的なオプションとスイッチの使用法をリストするには:
|
||||||
|
|
||||||
|
python sqlmap.py -h
|
||||||
|
|
||||||
|
全てのオプションとスイッチの使用法をリストするには:
|
||||||
|
|
||||||
|
python sqlmap.py -hh
|
||||||
|
|
||||||
|
実行例を [こちら](https://asciinema.org/a/46601) で見ることができます。
|
||||||
|
sqlmapの概要、機能の一覧、全てのオプションやスイッチの使用法を例とともに、 [ユーザーマニュアル](https://github.com/sqlmapproject/sqlmap/wiki) で確認することができます。
|
||||||
|
|
||||||
|
リンク
|
||||||
|
----
|
||||||
|
|
||||||
|
* ホームページ: http://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
|
||||||
|
* メーリングリストへの参加: https://lists.sourceforge.net/lists/listinfo/sqlmap-users
|
||||||
|
* メーリングリストのRSSフィード: http://rss.gmane.org/messages/complete/gmane.comp.security.sqlmap
|
||||||
|
* メーリングリストのアーカイブ: http://news.gmane.org/gmane.comp.security.sqlmap
|
||||||
|
* Twitter: [@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
|
||||||
@@ -34,7 +34,7 @@ Para obter a lista completa de opções faça:
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
Você pode encontrar alguns exemplos [aqui](https://gist.github.com/stamparm/5335217).
|
Você pode encontrar alguns exemplos [aqui](https://asciinema.org/a/46601).
|
||||||
Para ter uma visão geral dos recursos do sqlmap, lista de recursos suportados e a descrição de todas as opções, juntamente com exemplos, aconselhamos que você consulte o [manual do usuário](https://github.com/sqlmapproject/sqlmap/wiki).
|
Para ter uma visão geral dos recursos do sqlmap, lista de recursos suportados e a descrição de todas as opções, juntamente com exemplos, aconselhamos que você consulte o [manual do usuário](https://github.com/sqlmapproject/sqlmap/wiki).
|
||||||
|
|
||||||
Links
|
Links
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Bütün seçenekleri gösterir
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
Program ile ilgili örnekleri [burada](https://gist.github.com/stamparm/5335217) 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) bakmanızı tavsiye ediyoruz
|
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) bakmanızı tavsiye ediyoruz
|
||||||
|
|
||||||
Links
|
Links
|
||||||
----
|
----
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ sqlmap 可以运行在 [Python](http://www.python.org/download/) **2.6.x** 和
|
|||||||
|
|
||||||
python sqlmap.py -hh
|
python sqlmap.py -hh
|
||||||
|
|
||||||
你可以从 [这里](https://gist.github.com/stamparm/5335217) 看到一个sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki)。获取sqlmap所有支持的特性、参数、命令行选项开关及说明的使用帮助。
|
你可以从 [这里](https://asciinema.org/a/46601) 看到一个sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki)。获取sqlmap所有支持的特性、参数、命令行选项开关及说明的使用帮助。
|
||||||
|
|
||||||
链接
|
链接
|
||||||
----
|
----
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ void usage(char *path)
|
|||||||
printf(" -h this screen\n");
|
printf(" -h this screen\n");
|
||||||
printf(" -b num maximal number of blanks (unanswered icmp requests)\n");
|
printf(" -b num maximal number of blanks (unanswered icmp requests)\n");
|
||||||
printf(" before quitting\n");
|
printf(" before quitting\n");
|
||||||
printf(" -s bytes maximal data buffer size in bytes (default is 64 bytes)\n\n", DEFAULT_MAX_DATA_SIZE);
|
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("In order to improve the speed, lower the delay (-d) between requests or\n");
|
||||||
printf("increase the size (-s) of the data buffer\n");
|
printf("increase the size (-s) of the data buffer\n");
|
||||||
}
|
}
|
||||||
@@ -203,8 +203,6 @@ int main(int argc, char **argv)
|
|||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
int status;
|
int status;
|
||||||
unsigned int max_data_size;
|
unsigned int max_data_size;
|
||||||
struct hostent *he;
|
|
||||||
|
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
target = 0;
|
target = 0;
|
||||||
|
|||||||
@@ -48,9 +48,6 @@ def action():
|
|||||||
elif kb.nullConnection:
|
elif kb.nullConnection:
|
||||||
errMsg += ". You can try to rerun without using optimization "
|
errMsg += ". You can try to rerun without using optimization "
|
||||||
errMsg += "switch '%s'" % ("-o" if conf.optimize else "--null-connection")
|
errMsg += "switch '%s'" % ("-o" if conf.optimize else "--null-connection")
|
||||||
else:
|
|
||||||
errMsg += ". Support for this DBMS will be implemented at "
|
|
||||||
errMsg += "some point"
|
|
||||||
|
|
||||||
raise SqlmapUnsupportedDBMSException(errMsg)
|
raise SqlmapUnsupportedDBMSException(errMsg)
|
||||||
|
|
||||||
|
|||||||
+104
-46
@@ -7,6 +7,7 @@ See the file 'doc/COPYING' for copying permission
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import httplib
|
import httplib
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
@@ -54,6 +55,7 @@ from lib.core.enums import HASHDB_KEYS
|
|||||||
from lib.core.enums import HEURISTIC_TEST
|
from lib.core.enums import HEURISTIC_TEST
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.enums import HTTPMETHOD
|
from lib.core.enums import HTTPMETHOD
|
||||||
|
from lib.core.enums import NOTE
|
||||||
from lib.core.enums import NULLCONNECTION
|
from lib.core.enums import NULLCONNECTION
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
@@ -62,14 +64,15 @@ from lib.core.exception import SqlmapConnectionException
|
|||||||
from lib.core.exception import SqlmapNoneDataException
|
from lib.core.exception import SqlmapNoneDataException
|
||||||
from lib.core.exception import SqlmapSilentQuitException
|
from lib.core.exception import SqlmapSilentQuitException
|
||||||
from lib.core.exception import SqlmapUserQuitException
|
from lib.core.exception import SqlmapUserQuitException
|
||||||
from lib.core.settings import CLOUDFLARE_SERVER_HEADER
|
|
||||||
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
||||||
from lib.core.settings import DUMMY_NON_SQLI_CHECK_APPENDIX
|
from lib.core.settings import DUMMY_NON_SQLI_CHECK_APPENDIX
|
||||||
|
from lib.core.settings import FI_ERROR_REGEX
|
||||||
from lib.core.settings import FORMAT_EXCEPTION_STRINGS
|
from lib.core.settings import FORMAT_EXCEPTION_STRINGS
|
||||||
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
|
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
|
||||||
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
|
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
|
||||||
from lib.core.settings import IDS_WAF_CHECK_RATIO
|
from lib.core.settings import IDS_WAF_CHECK_RATIO
|
||||||
from lib.core.settings import IDS_WAF_CHECK_TIMEOUT
|
from lib.core.settings import IDS_WAF_CHECK_TIMEOUT
|
||||||
|
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
|
||||||
from lib.core.settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
|
from lib.core.settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
|
||||||
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
|
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
|
||||||
from lib.core.settings import SUPPORTED_DBMS
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
@@ -77,6 +80,7 @@ from lib.core.settings import URI_HTTP_HEADER
|
|||||||
from lib.core.settings import UPPER_RATIO_BOUND
|
from lib.core.settings import UPPER_RATIO_BOUND
|
||||||
from lib.core.threads import getCurrentThreadData
|
from lib.core.threads import getCurrentThreadData
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
|
from lib.request.comparison import comparison
|
||||||
from lib.request.inject import checkBooleanExpression
|
from lib.request.inject import checkBooleanExpression
|
||||||
from lib.request.templates import getPageTemplate
|
from lib.request.templates import getPageTemplate
|
||||||
from lib.techniques.union.test import unionTest
|
from lib.techniques.union.test import unionTest
|
||||||
@@ -97,6 +101,9 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
tests = getSortedInjectionTests()
|
tests = getSortedInjectionTests()
|
||||||
seenPayload = set()
|
seenPayload = set()
|
||||||
|
|
||||||
|
kb.data.setdefault("randomInt", str(randomInt(10)))
|
||||||
|
kb.data.setdefault("randomStr", str(randomStr(10)))
|
||||||
|
|
||||||
while tests:
|
while tests:
|
||||||
test = tests.pop(0)
|
test = tests.pop(0)
|
||||||
|
|
||||||
@@ -173,10 +180,11 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
lower, upper = int(match.group(1)), int(match.group(2))
|
lower, upper = int(match.group(1)), int(match.group(2))
|
||||||
for _ in (lower, upper):
|
for _ in (lower, upper):
|
||||||
if _ > 1:
|
if _ > 1:
|
||||||
|
__ = 2 * (_ - 1) + 1 if _ == lower else 2 * _
|
||||||
unionExtended = True
|
unionExtended = True
|
||||||
test.request.columns = re.sub(r"\b%d\b" % _, str(2 * _), test.request.columns)
|
test.request.columns = re.sub(r"\b%d\b" % _, str(__), test.request.columns)
|
||||||
title = re.sub(r"\b%d\b" % _, str(2 * _), title)
|
title = re.sub(r"\b%d\b" % _, str(__), title)
|
||||||
test.title = re.sub(r"\b%d\b" % _, str(2 * _), test.title)
|
test.title = re.sub(r"\b%d\b" % _, str(__), test.title)
|
||||||
|
|
||||||
# Skip test if the user's wants to test only for a specific
|
# Skip test if the user's wants to test only for a specific
|
||||||
# technique
|
# technique
|
||||||
@@ -380,8 +388,6 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
# Use different page template than the original
|
# Use different page template than the original
|
||||||
# one as we are changing parameters value, which
|
# one as we are changing parameters value, which
|
||||||
# will likely result in a different content
|
# will likely result in a different content
|
||||||
kb.data.setdefault("randomInt", str(randomInt(10)))
|
|
||||||
kb.data.setdefault("randomStr", str(randomStr(10)))
|
|
||||||
|
|
||||||
if conf.invalidLogical:
|
if conf.invalidLogical:
|
||||||
_ = int(kb.data.randomInt[:2])
|
_ = int(kb.data.randomInt[:2])
|
||||||
@@ -441,11 +447,13 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
kb.matchRatio = None
|
kb.matchRatio = None
|
||||||
kb.negativeLogic = (where == PAYLOAD.WHERE.NEGATIVE)
|
kb.negativeLogic = (where == PAYLOAD.WHERE.NEGATIVE)
|
||||||
Request.queryPage(genCmpPayload(), place, raise404=False)
|
Request.queryPage(genCmpPayload(), place, raise404=False)
|
||||||
falsePage = threadData.lastComparisonPage or ""
|
falsePage, falseHeaders, falseCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode
|
||||||
|
falseRawResponse = "%s%s" % (falseHeaders, falsePage)
|
||||||
|
|
||||||
# Perform the test's True request
|
# Perform the test's True request
|
||||||
trueResult = Request.queryPage(reqPayload, place, raise404=False)
|
trueResult = Request.queryPage(reqPayload, place, raise404=False)
|
||||||
truePage = threadData.lastComparisonPage or ""
|
truePage, trueHeaders, trueCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode
|
||||||
|
trueRawResponse = "%s%s" % (trueHeaders, truePage)
|
||||||
|
|
||||||
if trueResult and not(truePage == falsePage and not kb.nullConnection):
|
if trueResult and not(truePage == falsePage and not kb.nullConnection):
|
||||||
# Perform the test's False request
|
# Perform the test's False request
|
||||||
@@ -460,24 +468,59 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
errorResult = Request.queryPage(errorPayload, place, raise404=False)
|
errorResult = Request.queryPage(errorPayload, place, raise404=False)
|
||||||
if errorResult:
|
if errorResult:
|
||||||
continue
|
continue
|
||||||
|
elif not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
|
||||||
infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (paramType, parameter, title)
|
_ = comparison(kb.heuristicPage, None, getRatioValue=True)
|
||||||
logger.info(infoMsg)
|
if _ > kb.matchRatio:
|
||||||
|
kb.matchRatio = _
|
||||||
|
logger.debug("adjusting match ratio for current parameter to %.3f" % kb.matchRatio)
|
||||||
|
|
||||||
injectable = True
|
injectable = True
|
||||||
|
|
||||||
if not injectable and not any((conf.string, conf.notString, conf.regexp)) and kb.pageStable:
|
if injectable:
|
||||||
trueSet = set(extractTextTagContent(truePage))
|
if kb.pageStable and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
|
||||||
falseSet = set(extractTextTagContent(falsePage))
|
if all((falseCode, trueCode)) and falseCode != trueCode:
|
||||||
candidates = filter(None, (_.strip() if _.strip() in (kb.pageTemplate or "") and _.strip() not in falsePage and _.strip() not in threadData.lastComparisonHeaders else None for _ in (trueSet - falseSet)))
|
conf.code = trueCode
|
||||||
|
|
||||||
if candidates:
|
infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --code=%d)" % (paramType, parameter, title, conf.code)
|
||||||
conf.string = candidates[0]
|
logger.info(infoMsg)
|
||||||
infoMsg = "%s parameter '%s' seems to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'"))
|
else:
|
||||||
|
trueSet = set(extractTextTagContent(trueRawResponse))
|
||||||
|
trueSet = trueSet.union(__ for _ in trueSet for __ in _.split())
|
||||||
|
|
||||||
|
falseSet = set(extractTextTagContent(falseRawResponse))
|
||||||
|
falseSet = falseSet.union(__ for _ in falseSet for __ in _.split())
|
||||||
|
|
||||||
|
candidates = filter(None, (_.strip() if _.strip() in trueRawResponse and _.strip() not in falseRawResponse else None for _ in (trueSet - falseSet)))
|
||||||
|
|
||||||
|
if candidates:
|
||||||
|
candidates = sorted(candidates, key=lambda _: len(_))
|
||||||
|
for candidate in candidates:
|
||||||
|
if re.match(r"\A\w+\Z", candidate):
|
||||||
|
break
|
||||||
|
|
||||||
|
conf.string = candidate
|
||||||
|
|
||||||
|
infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'"))
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
if not any((conf.string, conf.notString)):
|
||||||
|
candidates = filter(None, (_.strip() if _.strip() in falseRawResponse and _.strip() not in trueRawResponse else None for _ in (falseSet - trueSet)))
|
||||||
|
|
||||||
|
if candidates:
|
||||||
|
candidates = sorted(candidates, key=lambda _: len(_))
|
||||||
|
for candidate in candidates:
|
||||||
|
if re.match(r"\A\w+\Z", candidate):
|
||||||
|
break
|
||||||
|
|
||||||
|
conf.notString = candidate
|
||||||
|
|
||||||
|
infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --not-string=\"%s\")" % (paramType, parameter, title, repr(conf.notString).lstrip('u').strip("'"))
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
if not any((conf.string, conf.notString, conf.code)):
|
||||||
|
infoMsg = "%s parameter '%s' appears to be '%s' injectable " % (paramType, parameter, title)
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
injectable = True
|
|
||||||
|
|
||||||
# In case of error-based SQL injection
|
# In case of error-based SQL injection
|
||||||
elif method == PAYLOAD.METHOD.GREP:
|
elif method == PAYLOAD.METHOD.GREP:
|
||||||
# Perform the test's request and grep the response
|
# Perform the test's request and grep the response
|
||||||
@@ -518,7 +561,7 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
trueResult = Request.queryPage(reqPayload, place, timeBasedCompare=True, raise404=False)
|
trueResult = Request.queryPage(reqPayload, place, timeBasedCompare=True, raise404=False)
|
||||||
|
|
||||||
if trueResult:
|
if trueResult:
|
||||||
infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (paramType, parameter, title)
|
infoMsg = "%s parameter '%s' appears to be '%s' injectable " % (paramType, parameter, title)
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
injectable = True
|
injectable = True
|
||||||
@@ -538,7 +581,7 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
warnMsg = "using unescaped version of the test "
|
warnMsg = "using unescaped version of the test "
|
||||||
warnMsg += "because of zero knowledge of the "
|
warnMsg += "because of zero knowledge of the "
|
||||||
warnMsg += "back-end DBMS. You can try to "
|
warnMsg += "back-end DBMS. You can try to "
|
||||||
warnMsg += "explicitly set it using option '--dbms'"
|
warnMsg += "explicitly set it with option '--dbms'"
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
else:
|
else:
|
||||||
Backend.forceDbms(kb.heuristicDbms)
|
Backend.forceDbms(kb.heuristicDbms)
|
||||||
@@ -627,6 +670,7 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
|
|
||||||
injection.conf.textOnly = conf.textOnly
|
injection.conf.textOnly = conf.textOnly
|
||||||
injection.conf.titles = conf.titles
|
injection.conf.titles = conf.titles
|
||||||
|
injection.conf.code = conf.code
|
||||||
injection.conf.string = conf.string
|
injection.conf.string = conf.string
|
||||||
injection.conf.notString = conf.notString
|
injection.conf.notString = conf.notString
|
||||||
injection.conf.regexp = conf.regexp
|
injection.conf.regexp = conf.regexp
|
||||||
@@ -691,19 +735,20 @@ def checkSqlInjection(place, parameter, value):
|
|||||||
# Return the injection object
|
# Return the injection object
|
||||||
if injection.place is not None and injection.parameter is not None:
|
if injection.place is not None and injection.parameter is not None:
|
||||||
if not conf.dropSetCookie and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data and injection.data[PAYLOAD.TECHNIQUE.BOOLEAN].vector.startswith('OR'):
|
if not conf.dropSetCookie and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data and injection.data[PAYLOAD.TECHNIQUE.BOOLEAN].vector.startswith('OR'):
|
||||||
warnMsg = "in OR boolean-based injections, please consider usage "
|
warnMsg = "in OR boolean-based injection cases, please consider usage "
|
||||||
warnMsg += "of switch '--drop-set-cookie' if you experience any "
|
warnMsg += "of switch '--drop-set-cookie' if you experience any "
|
||||||
warnMsg += "problems during data retrieval"
|
warnMsg += "problems during data retrieval"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
injection = checkFalsePositives(injection)
|
if not checkFalsePositives(injection):
|
||||||
|
|
||||||
if not injection:
|
|
||||||
kb.vulnHosts.remove(conf.hostname)
|
kb.vulnHosts.remove(conf.hostname)
|
||||||
|
if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection.notes:
|
||||||
|
injection.notes.append(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
injection = None
|
injection = None
|
||||||
|
|
||||||
if injection:
|
if injection and NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection.notes:
|
||||||
checkSuhosinPatch(injection)
|
checkSuhosinPatch(injection)
|
||||||
checkFilteredChars(injection)
|
checkFilteredChars(injection)
|
||||||
|
|
||||||
@@ -748,7 +793,7 @@ def checkFalsePositives(injection):
|
|||||||
Checks for false positives (only in single special cases)
|
Checks for false positives (only in single special cases)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
retVal = injection
|
retVal = True
|
||||||
|
|
||||||
if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or\
|
if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or\
|
||||||
(len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title):
|
(len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title):
|
||||||
@@ -774,7 +819,7 @@ def checkFalsePositives(injection):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not checkBooleanExpression("%d=%d" % (randInt1, randInt1)):
|
if not checkBooleanExpression("%d=%d" % (randInt1, randInt1)):
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
# Just in case if DBMS hasn't properly recovered from previous delayed request
|
# Just in case if DBMS hasn't properly recovered from previous delayed request
|
||||||
@@ -782,22 +827,22 @@ def checkFalsePositives(injection):
|
|||||||
checkBooleanExpression("%d=%d" % (randInt1, randInt2))
|
checkBooleanExpression("%d=%d" % (randInt1, randInt2))
|
||||||
|
|
||||||
if checkBooleanExpression("%d=%d" % (randInt1, randInt3)): # this must not be evaluated to True
|
if checkBooleanExpression("%d=%d" % (randInt1, randInt3)): # this must not be evaluated to True
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
elif checkBooleanExpression("%d=%d" % (randInt3, randInt2)): # this must not be evaluated to True
|
elif checkBooleanExpression("%d=%d" % (randInt3, randInt2)): # this must not be evaluated to True
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
elif not checkBooleanExpression("%d=%d" % (randInt2, randInt2)): # this must be evaluated to True
|
elif not checkBooleanExpression("%d=%d" % (randInt2, randInt2)): # this must be evaluated to True
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
elif checkBooleanExpression("%d %d" % (randInt3, randInt2)): # this must not be evaluated to True (invalid statement)
|
elif checkBooleanExpression("%d %d" % (randInt3, randInt2)): # this must not be evaluated to True (invalid statement)
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
if retVal is None:
|
if not retVal:
|
||||||
warnMsg = "false positive or unexploitable injection point detected"
|
warnMsg = "false positive or unexploitable injection point detected"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
@@ -885,6 +930,7 @@ def heuristicCheckSqlInjection(place, parameter):
|
|||||||
payload = agent.payload(place, parameter, newValue=payload)
|
payload = agent.payload(place, parameter, newValue=payload)
|
||||||
page, _ = Request.queryPage(payload, place, content=True, raise404=False)
|
page, _ = Request.queryPage(payload, place, content=True, raise404=False)
|
||||||
|
|
||||||
|
kb.heuristicPage = page
|
||||||
kb.heuristicMode = False
|
kb.heuristicMode = False
|
||||||
|
|
||||||
parseFilePaths(page)
|
parseFilePaths(page)
|
||||||
@@ -906,7 +952,7 @@ def heuristicCheckSqlInjection(place, parameter):
|
|||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
randStr = randomStr()
|
randStr = randomStr()
|
||||||
payload = "%s%s%s" % (prefix, "%s%s" % (origValue, randStr), suffix)
|
payload = "%s%s%s" % (prefix, "%s.%d%s" % (origValue, random.randint(1, 9), randStr), suffix)
|
||||||
payload = agent.payload(place, parameter, newValue=payload, where=PAYLOAD.WHERE.REPLACE)
|
payload = agent.payload(place, parameter, newValue=payload, where=PAYLOAD.WHERE.REPLACE)
|
||||||
casting = Request.queryPage(payload, place, raise404=False)
|
casting = Request.queryPage(payload, place, raise404=False)
|
||||||
|
|
||||||
@@ -947,7 +993,7 @@ def heuristicCheckSqlInjection(place, parameter):
|
|||||||
infoMsg += "'%s' might be vulnerable to cross-site scripting attacks" % parameter
|
infoMsg += "'%s' might be vulnerable to cross-site scripting attacks" % parameter
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
for match in re.finditer("(?i)[^\n]*(no such file|failed (to )?open)[^\n]*", page or ""):
|
for match in re.finditer(FI_ERROR_REGEX, page or ""):
|
||||||
if randStr1.lower() in match.group(0).lower():
|
if randStr1.lower() in match.group(0).lower():
|
||||||
infoMsg = "heuristic (FI) test shows that %s parameter " % paramType
|
infoMsg = "heuristic (FI) test shows that %s parameter " % paramType
|
||||||
infoMsg += "'%s' might be vulnerable to file inclusion attacks" % parameter
|
infoMsg += "'%s' might be vulnerable to file inclusion attacks" % parameter
|
||||||
@@ -1013,12 +1059,22 @@ def checkDynamicContent(firstPage, secondPage):
|
|||||||
logger.critical(warnMsg)
|
logger.critical(warnMsg)
|
||||||
return
|
return
|
||||||
|
|
||||||
seqMatcher = getCurrentThreadData().seqMatcher
|
if firstPage and secondPage and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (firstPage, secondPage)):
|
||||||
seqMatcher.set_seq1(firstPage)
|
ratio = None
|
||||||
seqMatcher.set_seq2(secondPage)
|
else:
|
||||||
|
try:
|
||||||
|
seqMatcher = getCurrentThreadData().seqMatcher
|
||||||
|
seqMatcher.set_seq1(firstPage)
|
||||||
|
seqMatcher.set_seq2(secondPage)
|
||||||
|
ratio = seqMatcher.quick_ratio()
|
||||||
|
except MemoryError:
|
||||||
|
ratio = None
|
||||||
|
|
||||||
|
if ratio is None:
|
||||||
|
kb.skipSeqMatcher = True
|
||||||
|
|
||||||
# In case of an intolerable difference turn on dynamicity removal engine
|
# In case of an intolerable difference turn on dynamicity removal engine
|
||||||
if seqMatcher.quick_ratio() <= UPPER_RATIO_BOUND:
|
elif ratio <= UPPER_RATIO_BOUND:
|
||||||
findDynamicContent(firstPage, secondPage)
|
findDynamicContent(firstPage, secondPage)
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
@@ -1235,6 +1291,9 @@ def identifyWaf():
|
|||||||
if not conf.identifyWaf:
|
if not conf.identifyWaf:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if not kb.wafFunctions:
|
||||||
|
setWafFunctions()
|
||||||
|
|
||||||
kb.testMode = True
|
kb.testMode = True
|
||||||
|
|
||||||
infoMsg = "using WAF scripts to detect "
|
infoMsg = "using WAF scripts to detect "
|
||||||
@@ -1276,7 +1335,7 @@ def identifyWaf():
|
|||||||
break
|
break
|
||||||
|
|
||||||
if retVal:
|
if retVal:
|
||||||
errMsg = "WAF/IDS/IPS identified '%s'. Please " % retVal
|
errMsg = "WAF/IDS/IPS identified as '%s'. Please " % retVal
|
||||||
errMsg += "consider usage of tamper scripts (option '--tamper')"
|
errMsg += "consider usage of tamper scripts (option '--tamper')"
|
||||||
logger.critical(errMsg)
|
logger.critical(errMsg)
|
||||||
|
|
||||||
@@ -1287,7 +1346,7 @@ def identifyWaf():
|
|||||||
if output and output[0] not in ("Y", "y"):
|
if output and output[0] not in ("Y", "y"):
|
||||||
raise SqlmapUserQuitException
|
raise SqlmapUserQuitException
|
||||||
else:
|
else:
|
||||||
warnMsg = "no WAF/IDS/IPS product has been identified (this doesn't mean that there is none)"
|
warnMsg = "WAF/IDS/IPS product hasn't been identified"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
kb.testType = None
|
kb.testType = None
|
||||||
@@ -1383,10 +1442,6 @@ def checkConnection(suppressOutput=False):
|
|||||||
else:
|
else:
|
||||||
kb.errorIsNone = True
|
kb.errorIsNone = True
|
||||||
|
|
||||||
if headers and headers.get("Server", "") == CLOUDFLARE_SERVER_HEADER:
|
|
||||||
warnMsg = "CloudFlare response detected"
|
|
||||||
logger.warn(warnMsg)
|
|
||||||
|
|
||||||
except SqlmapConnectionException, ex:
|
except SqlmapConnectionException, ex:
|
||||||
if conf.ipv6:
|
if conf.ipv6:
|
||||||
warnMsg = "check connection to a provided "
|
warnMsg = "check connection to a provided "
|
||||||
@@ -1415,3 +1470,6 @@ def checkConnection(suppressOutput=False):
|
|||||||
|
|
||||||
def setVerbosity(): # Cross-linked function
|
def setVerbosity(): # Cross-linked function
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def setWafFunctions(): # Cross-linked function
|
||||||
|
raise NotImplementedError
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ from lib.core.enums import CONTENT_TYPE
|
|||||||
from lib.core.enums import HASHDB_KEYS
|
from lib.core.enums import HASHDB_KEYS
|
||||||
from lib.core.enums import HEURISTIC_TEST
|
from lib.core.enums import HEURISTIC_TEST
|
||||||
from lib.core.enums import HTTPMETHOD
|
from lib.core.enums import HTTPMETHOD
|
||||||
|
from lib.core.enums import NOTE
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
from lib.core.exception import SqlmapBaseException
|
from lib.core.exception import SqlmapBaseException
|
||||||
@@ -225,23 +226,23 @@ def _saveToResultsFile():
|
|||||||
results = {}
|
results = {}
|
||||||
techniques = dict(map(lambda x: (x[1], x[0]), getPublicTypeMembers(PAYLOAD.TECHNIQUE)))
|
techniques = dict(map(lambda x: (x[1], x[0]), getPublicTypeMembers(PAYLOAD.TECHNIQUE)))
|
||||||
|
|
||||||
for inj in kb.injections:
|
for injection in kb.injections + kb.falsePositives:
|
||||||
if inj.place is None or inj.parameter is None:
|
if injection.place is None or injection.parameter is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
key = (inj.place, inj.parameter)
|
key = (injection.place, injection.parameter, ';'.join(injection.notes))
|
||||||
if key not in results:
|
if key not in results:
|
||||||
results[key] = []
|
results[key] = []
|
||||||
|
|
||||||
results[key].extend(inj.data.keys())
|
results[key].extend(injection.data.keys())
|
||||||
|
|
||||||
for key, value in results.items():
|
for key, value in results.items():
|
||||||
place, parameter = key
|
place, parameter, notes = key
|
||||||
line = "%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(map(lambda x: techniques[x][0].upper(), sorted(value))), os.linesep)
|
line = "%s,%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(map(lambda x: techniques[x][0].upper(), sorted(value))), notes, os.linesep)
|
||||||
conf.resultsFP.writelines(line)
|
conf.resultsFP.writelines(line)
|
||||||
|
|
||||||
if not results:
|
if not results:
|
||||||
line = "%s,,,%s" % (conf.url, os.linesep)
|
line = "%s,,,,%s" % (conf.url, os.linesep)
|
||||||
conf.resultsFP.writelines(line)
|
conf.resultsFP.writelines(line)
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
@@ -463,7 +464,7 @@ def start():
|
|||||||
infoMsg = "skipping randomizing %s parameter '%s'" % (paramType, parameter)
|
infoMsg = "skipping randomizing %s parameter '%s'" % (paramType, parameter)
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
elif parameter in conf.skip:
|
elif parameter in conf.skip or kb.postHint and parameter.split(' ')[-1] in conf.skip:
|
||||||
testSqlInj = False
|
testSqlInj = False
|
||||||
|
|
||||||
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
|
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
|
||||||
@@ -520,23 +521,30 @@ def start():
|
|||||||
|
|
||||||
injection = checkSqlInjection(place, parameter, value)
|
injection = checkSqlInjection(place, parameter, value)
|
||||||
proceed = not kb.endDetection
|
proceed = not kb.endDetection
|
||||||
|
injectable = False
|
||||||
|
|
||||||
if injection is not None and injection.place is not None:
|
if getattr(injection, "place", None) is not None:
|
||||||
kb.injections.append(injection)
|
if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE in injection.notes:
|
||||||
|
kb.falsePositives.append(injection)
|
||||||
|
else:
|
||||||
|
injectable = True
|
||||||
|
|
||||||
# In case when user wants to end detection phase (Ctrl+C)
|
kb.injections.append(injection)
|
||||||
if not proceed:
|
|
||||||
break
|
|
||||||
|
|
||||||
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
|
# In case when user wants to end detection phase (Ctrl+C)
|
||||||
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
|
if not proceed:
|
||||||
test = readInput(msg, default="N")
|
break
|
||||||
|
|
||||||
if test[0] not in ("y", "Y"):
|
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
|
||||||
proceed = False
|
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
|
||||||
paramKey = (conf.hostname, conf.path, None, None)
|
test = readInput(msg, default="N")
|
||||||
kb.testedParams.add(paramKey)
|
|
||||||
else:
|
if test[0] not in ("y", "Y"):
|
||||||
|
proceed = False
|
||||||
|
paramKey = (conf.hostname, conf.path, None, None)
|
||||||
|
kb.testedParams.add(paramKey)
|
||||||
|
|
||||||
|
if not injectable:
|
||||||
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
|
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
|
||||||
warnMsg += "injectable"
|
warnMsg += "injectable"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
@@ -585,24 +593,24 @@ def start():
|
|||||||
if not conf.string and not conf.notString and not conf.regexp:
|
if not conf.string and not conf.notString and not conf.regexp:
|
||||||
errMsg += " Also, you can try to rerun by providing "
|
errMsg += " Also, you can try to rerun by providing "
|
||||||
errMsg += "either a valid value for option '--string' "
|
errMsg += "either a valid value for option '--string' "
|
||||||
errMsg += "(or '--regexp')"
|
errMsg += "(or '--regexp')."
|
||||||
elif conf.string:
|
elif conf.string:
|
||||||
errMsg += " Also, you can try to rerun by providing a "
|
errMsg += " Also, you can try to rerun by providing a "
|
||||||
errMsg += "valid value for option '--string' as perhaps the string you "
|
errMsg += "valid value for option '--string' as perhaps the string you "
|
||||||
errMsg += "have chosen does not match "
|
errMsg += "have chosen does not match "
|
||||||
errMsg += "exclusively True responses"
|
errMsg += "exclusively True responses."
|
||||||
elif conf.regexp:
|
elif conf.regexp:
|
||||||
errMsg += " Also, you can try to rerun by providing a "
|
errMsg += " Also, you can try to rerun by providing a "
|
||||||
errMsg += "valid value for option '--regexp' as perhaps the regular "
|
errMsg += "valid value for option '--regexp' as perhaps the regular "
|
||||||
errMsg += "expression that you have chosen "
|
errMsg += "expression that you have chosen "
|
||||||
errMsg += "does not match exclusively True responses"
|
errMsg += "does not match exclusively True responses."
|
||||||
|
|
||||||
if not conf.tamper:
|
if not conf.tamper:
|
||||||
errMsg += " If you suspect that there is some kind of protection mechanism "
|
errMsg += " If you suspect that there is some kind of protection mechanism "
|
||||||
errMsg += "involved (e.g. WAF) maybe you could retry "
|
errMsg += "involved (e.g. WAF) maybe you could retry "
|
||||||
errMsg += "with an option '--tamper' (e.g. '--tamper=space2comment')"
|
errMsg += "with an option '--tamper' (e.g. '--tamper=space2comment')"
|
||||||
|
|
||||||
raise SqlmapNotVulnerableException(errMsg)
|
raise SqlmapNotVulnerableException(errMsg.rstrip('.'))
|
||||||
else:
|
else:
|
||||||
# Flush the flag
|
# Flush the flag
|
||||||
kb.testMode = False
|
kb.testMode = False
|
||||||
@@ -651,6 +659,8 @@ def start():
|
|||||||
errMsg = getSafeExString(ex)
|
errMsg = getSafeExString(ex)
|
||||||
|
|
||||||
if conf.multipleTargets:
|
if conf.multipleTargets:
|
||||||
|
_saveToResultsFile()
|
||||||
|
|
||||||
errMsg += ", skipping to the next %s" % ("form" if conf.forms else "URL")
|
errMsg += ", skipping to the next %s" % ("form" if conf.forms else "URL")
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
else:
|
else:
|
||||||
@@ -669,9 +679,10 @@ def start():
|
|||||||
if kb.dataOutputFlag and not conf.multipleTargets:
|
if kb.dataOutputFlag and not conf.multipleTargets:
|
||||||
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
|
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
|
||||||
|
|
||||||
if conf.multipleTargets and conf.resultsFilename:
|
if conf.multipleTargets:
|
||||||
infoMsg = "you can find results of scanning in multiple targets "
|
if conf.resultsFilename:
|
||||||
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFilename
|
infoMsg = "you can find results of scanning in multiple targets "
|
||||||
logger.info(infoMsg)
|
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFilename
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ See the file 'doc/COPYING' for copying permission
|
|||||||
|
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.dicts import DBMS_DICT
|
from lib.core.dicts import DBMS_DICT
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
@@ -101,7 +102,10 @@ def setHandler():
|
|||||||
conf.dbmsConnector.connect()
|
conf.dbmsConnector.connect()
|
||||||
|
|
||||||
if handler.checkDbms():
|
if handler.checkDbms():
|
||||||
conf.dbmsHandler = handler
|
if kb.resolutionDbms:
|
||||||
|
conf.dbmsHandler = max(_ for _ in items if _[0] == kb.resolutionDbms)[2]()
|
||||||
|
else:
|
||||||
|
conf.dbmsHandler = handler
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
conf.dbmsConnector = None
|
conf.dbmsConnector = None
|
||||||
|
|||||||
+24
-9
@@ -35,10 +35,12 @@ from lib.core.enums import PLACE
|
|||||||
from lib.core.enums import POST_HINT
|
from lib.core.enums import POST_HINT
|
||||||
from lib.core.exception import SqlmapNoneDataException
|
from lib.core.exception import SqlmapNoneDataException
|
||||||
from lib.core.settings import BOUNDARY_BACKSLASH_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 CUSTOM_INJECTION_MARK_CHAR
|
||||||
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
|
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
|
||||||
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
||||||
from lib.core.settings import GENERIC_SQL_COMMENT
|
from lib.core.settings import GENERIC_SQL_COMMENT
|
||||||
|
from lib.core.settings import NULL
|
||||||
from lib.core.settings import PAYLOAD_DELIMITER
|
from lib.core.settings import PAYLOAD_DELIMITER
|
||||||
from lib.core.settings import REPLACEMENT_MARKER
|
from lib.core.settings import REPLACEMENT_MARKER
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
@@ -95,9 +97,12 @@ class Agent(object):
|
|||||||
paramDict = conf.paramDict[place]
|
paramDict = conf.paramDict[place]
|
||||||
origValue = getUnicode(paramDict[parameter])
|
origValue = getUnicode(paramDict[parameter])
|
||||||
|
|
||||||
if place == PLACE.URI:
|
if place == PLACE.URI or BOUNDED_INJECTION_MARKER in origValue:
|
||||||
paramString = origValue
|
paramString = origValue
|
||||||
origValue = origValue.split(CUSTOM_INJECTION_MARK_CHAR)[0]
|
if place == PLACE.URI:
|
||||||
|
origValue = origValue.split(CUSTOM_INJECTION_MARK_CHAR)[0]
|
||||||
|
else:
|
||||||
|
origValue = filter(None, (re.search(_, origValue.split(BOUNDED_INJECTION_MARKER)[0]) for _ in (r"\w+\Z", r"[^\"'><]+\Z", r"[^ ]+\Z")))[0].group(0)
|
||||||
origValue = origValue[origValue.rfind('/') + 1:]
|
origValue = origValue[origValue.rfind('/') + 1:]
|
||||||
for char in ('?', '=', ':'):
|
for char in ('?', '=', ':'):
|
||||||
if char in origValue:
|
if char in origValue:
|
||||||
@@ -161,6 +166,9 @@ class Agent(object):
|
|||||||
newValue = newValue.replace(CUSTOM_INJECTION_MARK_CHAR, REPLACEMENT_MARKER)
|
newValue = newValue.replace(CUSTOM_INJECTION_MARK_CHAR, REPLACEMENT_MARKER)
|
||||||
retVal = paramString.replace(_, self.addPayloadDelimiters(newValue))
|
retVal = paramString.replace(_, self.addPayloadDelimiters(newValue))
|
||||||
retVal = retVal.replace(CUSTOM_INJECTION_MARK_CHAR, "").replace(REPLACEMENT_MARKER, CUSTOM_INJECTION_MARK_CHAR)
|
retVal = retVal.replace(CUSTOM_INJECTION_MARK_CHAR, "").replace(REPLACEMENT_MARKER, CUSTOM_INJECTION_MARK_CHAR)
|
||||||
|
elif BOUNDED_INJECTION_MARKER in paramDict[parameter]:
|
||||||
|
_ = "%s%s" % (origValue, BOUNDED_INJECTION_MARKER)
|
||||||
|
retVal = "%s=%s" % (re.sub(r" (\#\d\*|\(.+\))\Z", "", parameter), paramString.replace(_, self.addPayloadDelimiters(newValue)))
|
||||||
elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST):
|
elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST):
|
||||||
retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue))
|
retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue))
|
||||||
else:
|
else:
|
||||||
@@ -273,7 +281,7 @@ class Agent(object):
|
|||||||
where = kb.injection.data[kb.technique].where if where is None else where
|
where = kb.injection.data[kb.technique].where if where is None else where
|
||||||
comment = kb.injection.data[kb.technique].comment if comment is None else comment
|
comment = kb.injection.data[kb.technique].comment if comment is None else comment
|
||||||
|
|
||||||
if Backend.getIdentifiedDbms() == DBMS.ACCESS and comment == GENERIC_SQL_COMMENT:
|
if Backend.getIdentifiedDbms() == DBMS.ACCESS and any((comment or "").startswith(_) for _ in ("--", "[GENERIC_SQL_COMMENT]")):
|
||||||
comment = queries[DBMS.ACCESS].comment.query
|
comment = queries[DBMS.ACCESS].comment.query
|
||||||
|
|
||||||
if comment is not None:
|
if comment is not None:
|
||||||
@@ -296,7 +304,7 @@ class Agent(object):
|
|||||||
_ = (
|
_ = (
|
||||||
("[DELIMITER_START]", kb.chars.start), ("[DELIMITER_STOP]", kb.chars.stop),\
|
("[DELIMITER_START]", kb.chars.start), ("[DELIMITER_STOP]", kb.chars.stop),\
|
||||||
("[AT_REPLACE]", kb.chars.at), ("[SPACE_REPLACE]", kb.chars.space), ("[DOLLAR_REPLACE]", kb.chars.dollar),\
|
("[AT_REPLACE]", kb.chars.at), ("[SPACE_REPLACE]", kb.chars.space), ("[DOLLAR_REPLACE]", kb.chars.dollar),\
|
||||||
("[HASH_REPLACE]", kb.chars.hash_),
|
("[HASH_REPLACE]", kb.chars.hash_), ("[GENERIC_SQL_COMMENT]", GENERIC_SQL_COMMENT)
|
||||||
)
|
)
|
||||||
payload = reduce(lambda x, y: x.replace(y[0], y[1]), _, payload)
|
payload = reduce(lambda x, y: x.replace(y[0], y[1]), _, payload)
|
||||||
|
|
||||||
@@ -713,8 +721,11 @@ class Agent(object):
|
|||||||
|
|
||||||
if conf.uFrom:
|
if conf.uFrom:
|
||||||
fromTable = " FROM %s" % conf.uFrom
|
fromTable = " FROM %s" % conf.uFrom
|
||||||
else:
|
elif not fromTable:
|
||||||
fromTable = fromTable or FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), "")
|
if kb.tableFrom:
|
||||||
|
fromTable = " FROM %s" % kb.tableFrom
|
||||||
|
else:
|
||||||
|
fromTable = FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), "")
|
||||||
|
|
||||||
if query.startswith("SELECT "):
|
if query.startswith("SELECT "):
|
||||||
query = query[len("SELECT "):]
|
query = query[len("SELECT "):]
|
||||||
@@ -747,6 +758,9 @@ class Agent(object):
|
|||||||
intoRegExp = intoRegExp.group(1)
|
intoRegExp = intoRegExp.group(1)
|
||||||
query = query[:query.index(intoRegExp)]
|
query = query[:query.index(intoRegExp)]
|
||||||
|
|
||||||
|
position = 0
|
||||||
|
char = NULL
|
||||||
|
|
||||||
for element in xrange(0, count):
|
for element in xrange(0, count):
|
||||||
if element > 0:
|
if element > 0:
|
||||||
unionQuery += ','
|
unionQuery += ','
|
||||||
@@ -985,12 +999,13 @@ class Agent(object):
|
|||||||
|
|
||||||
def forgeQueryOutputLength(self, expression):
|
def forgeQueryOutputLength(self, expression):
|
||||||
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
|
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
|
||||||
select = re.search("\ASELECT\s+", expression, re.I)
|
select = re.search(r"\ASELECT\s+", expression, re.I)
|
||||||
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
selectTopExpr = re.search(r"\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
||||||
|
selectMinMaxExpr = re.search(r"\ASELECT\s+(MIN|MAX)\(.+?\)\s+FROM", expression, re.I)
|
||||||
|
|
||||||
_, _, _, _, _, _, fieldsStr, _ = self.getFields(expression)
|
_, _, _, _, _, _, fieldsStr, _ = self.getFields(expression)
|
||||||
|
|
||||||
if selectTopExpr:
|
if selectTopExpr or selectMinMaxExpr:
|
||||||
lengthExpr = lengthQuery % ("(%s)" % expression)
|
lengthExpr = lengthQuery % ("(%s)" % expression)
|
||||||
elif select:
|
elif select:
|
||||||
lengthExpr = expression.replace(fieldsStr, lengthQuery % fieldsStr, 1)
|
lengthExpr = expression.replace(fieldsStr, lengthQuery % fieldsStr, 1)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
from lib.core.enums import MKSTEMP_PREFIX
|
||||||
from lib.core.exception import SqlmapSystemException
|
from lib.core.exception import SqlmapSystemException
|
||||||
from lib.core.settings import BIGARRAY_CHUNK_SIZE
|
from lib.core.settings import BIGARRAY_CHUNK_SIZE
|
||||||
|
|
||||||
@@ -91,7 +92,7 @@ class BigArray(list):
|
|||||||
|
|
||||||
def _dump(self, chunk):
|
def _dump(self, chunk):
|
||||||
try:
|
try:
|
||||||
handle, filename = tempfile.mkstemp()
|
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY)
|
||||||
self.filenames.add(filename)
|
self.filenames.add(filename)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
with open(filename, "w+b") as fp:
|
with open(filename, "w+b") as fp:
|
||||||
|
|||||||
+145
-58
@@ -72,6 +72,7 @@ from lib.core.enums import EXPECTED
|
|||||||
from lib.core.enums import HEURISTIC_TEST
|
from lib.core.enums import HEURISTIC_TEST
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.enums import HTTPMETHOD
|
from lib.core.enums import HTTPMETHOD
|
||||||
|
from lib.core.enums import MKSTEMP_PREFIX
|
||||||
from lib.core.enums import OS
|
from lib.core.enums import OS
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
@@ -91,6 +92,7 @@ from lib.core.log import LOGGER_HANDLER
|
|||||||
from lib.core.optiondict import optDict
|
from lib.core.optiondict import optDict
|
||||||
from lib.core.settings import BANNER
|
from lib.core.settings import BANNER
|
||||||
from lib.core.settings import BOLD_PATTERNS
|
from lib.core.settings import BOLD_PATTERNS
|
||||||
|
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_PREFIXES
|
||||||
from lib.core.settings import BRUTE_DOC_ROOT_SUFFIXES
|
from lib.core.settings import BRUTE_DOC_ROOT_SUFFIXES
|
||||||
from lib.core.settings import BRUTE_DOC_ROOT_TARGET_MARK
|
from lib.core.settings import BRUTE_DOC_ROOT_TARGET_MARK
|
||||||
@@ -102,6 +104,7 @@ from lib.core.settings import DEFAULT_MSSQL_SCHEMA
|
|||||||
from lib.core.settings import DUMMY_USER_INJECTION
|
from lib.core.settings import DUMMY_USER_INJECTION
|
||||||
from lib.core.settings import DYNAMICITY_MARK_LENGTH
|
from lib.core.settings import DYNAMICITY_MARK_LENGTH
|
||||||
from lib.core.settings import ERROR_PARSING_REGEXES
|
from lib.core.settings import ERROR_PARSING_REGEXES
|
||||||
|
from lib.core.settings import FILE_PATH_REGEXES
|
||||||
from lib.core.settings import FORCE_COOKIE_EXPIRATION_TIME
|
from lib.core.settings import FORCE_COOKIE_EXPIRATION_TIME
|
||||||
from lib.core.settings import FORM_SEARCH_REGEX
|
from lib.core.settings import FORM_SEARCH_REGEX
|
||||||
from lib.core.settings import GENERIC_DOC_ROOT_DIRECTORY_NAMES
|
from lib.core.settings import GENERIC_DOC_ROOT_DIRECTORY_NAMES
|
||||||
@@ -151,6 +154,7 @@ from lib.core.threads import getCurrentThreadData
|
|||||||
from lib.utils.sqlalchemy import _sqlalchemy
|
from lib.utils.sqlalchemy import _sqlalchemy
|
||||||
from thirdparty.clientform.clientform import ParseResponse
|
from thirdparty.clientform.clientform import ParseResponse
|
||||||
from thirdparty.clientform.clientform import ParseError
|
from thirdparty.clientform.clientform import ParseError
|
||||||
|
from thirdparty.colorama.initialise import init as coloramainit
|
||||||
from thirdparty.magic import magic
|
from thirdparty.magic import magic
|
||||||
from thirdparty.odict.odict import OrderedDict
|
from thirdparty.odict.odict import OrderedDict
|
||||||
from thirdparty.termcolor.termcolor import colored
|
from thirdparty.termcolor.termcolor import colored
|
||||||
@@ -302,7 +306,7 @@ class Backend:
|
|||||||
|
|
||||||
# Little precaution, in theory this condition should always be false
|
# Little precaution, in theory this condition should always be false
|
||||||
elif kb.dbms is not None and kb.dbms != dbms:
|
elif kb.dbms is not None and kb.dbms != dbms:
|
||||||
warnMsg = "there seems to be a high probability that "
|
warnMsg = "there appears to be a high probability that "
|
||||||
warnMsg += "this could be a false positive case"
|
warnMsg += "this could be a false positive case"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
@@ -316,6 +320,8 @@ class Backend:
|
|||||||
_ = readInput(msg, default=kb.dbms)
|
_ = readInput(msg, default=kb.dbms)
|
||||||
|
|
||||||
if aliasToDbmsEnum(_) == kb.dbms:
|
if aliasToDbmsEnum(_) == kb.dbms:
|
||||||
|
kb.dbmsVersion = []
|
||||||
|
kb.resolutionDbms = kb.dbms
|
||||||
break
|
break
|
||||||
elif aliasToDbmsEnum(_) == dbms:
|
elif aliasToDbmsEnum(_) == dbms:
|
||||||
kb.dbms = aliasToDbmsEnum(_)
|
kb.dbms = aliasToDbmsEnum(_)
|
||||||
@@ -579,7 +585,7 @@ def paramToDict(place, parameters=None):
|
|||||||
if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken):
|
if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken):
|
||||||
_ = urldecode(testableParameters[parameter], convall=True)
|
_ = urldecode(testableParameters[parameter], convall=True)
|
||||||
if (_.endswith("'") and _.count("'") == 1
|
if (_.endswith("'") and _.count("'") == 1
|
||||||
or re.search(r'\A9{3,}', _) or re.search(DUMMY_USER_INJECTION, _))\
|
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):
|
and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX):
|
||||||
warnMsg = "it appears that you have provided tainted parameter values "
|
warnMsg = "it appears that you have provided tainted parameter values "
|
||||||
warnMsg += "('%s') with most probably leftover " % element
|
warnMsg += "('%s') with most probably leftover " % element
|
||||||
@@ -598,27 +604,78 @@ def paramToDict(place, parameters=None):
|
|||||||
warnMsg += "so sqlmap could be able to run properly"
|
warnMsg += "so sqlmap could be able to run properly"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if conf.testParameter and not testableParameters:
|
if place in (PLACE.POST, PLACE.GET):
|
||||||
paramStr = ", ".join(test for test in conf.testParameter)
|
for regex in (r"\A((?:<[^>]+>)+\w+)((?:<[^>]+>)+)\Z", r"\A([^\w]+.*\w+)([^\w]+)\Z"):
|
||||||
|
match = re.search(regex, testableParameters[parameter])
|
||||||
|
if match:
|
||||||
|
try:
|
||||||
|
candidates = OrderedDict()
|
||||||
|
|
||||||
if len(conf.testParameter) > 1:
|
def walk(head, current=None):
|
||||||
warnMsg = "provided parameters '%s' " % paramStr
|
current = current or head
|
||||||
warnMsg += "are not inside the %s" % place
|
if isListLike(current):
|
||||||
logger.warn(warnMsg)
|
for _ in current:
|
||||||
else:
|
walk(head, _)
|
||||||
parameter = conf.testParameter[0]
|
elif isinstance(current, dict):
|
||||||
|
for key in current.keys():
|
||||||
|
value = current[key]
|
||||||
|
if isinstance(value, (list, tuple, set, dict)):
|
||||||
|
walk(head, value)
|
||||||
|
elif isinstance(value, (bool, int, float, basestring)):
|
||||||
|
original = current[key]
|
||||||
|
if isinstance(value, bool):
|
||||||
|
current[key] = "%s%s" % (str(value).lower(), BOUNDED_INJECTION_MARKER)
|
||||||
|
else:
|
||||||
|
current[key] = "%s%s" % (value, BOUNDED_INJECTION_MARKER)
|
||||||
|
candidates["%s (%s)" % (parameter, key)] = json.dumps(deserialized)
|
||||||
|
current[key] = original
|
||||||
|
|
||||||
if not intersect(USER_AGENT_ALIASES + REFERER_ALIASES + HOST_ALIASES, parameter, True):
|
deserialized = json.loads(testableParameters[parameter])
|
||||||
debugMsg = "provided parameter '%s' " % paramStr
|
walk(deserialized)
|
||||||
debugMsg += "is not inside the %s" % place
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
elif len(conf.testParameter) != len(testableParameters.keys()):
|
if candidates:
|
||||||
for parameter in conf.testParameter:
|
message = "it appears that provided value for %s parameter '%s' " % (place, parameter)
|
||||||
if parameter not in testableParameters:
|
message += "is JSON deserializable. Do you want to inject inside? [y/N] "
|
||||||
debugMsg = "provided parameter '%s' " % parameter
|
test = readInput(message, default="N")
|
||||||
debugMsg += "is not inside the %s" % place
|
if test[0] in ("y", "Y"):
|
||||||
logger.debug(debugMsg)
|
del testableParameters[parameter]
|
||||||
|
testableParameters.update(candidates)
|
||||||
|
break
|
||||||
|
except (KeyboardInterrupt, SqlmapUserQuitException):
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
_ = re.sub(regex, "\g<1>%s\g<%d>" % (CUSTOM_INJECTION_MARK_CHAR, len(match.groups())), testableParameters[parameter])
|
||||||
|
message = "it appears that provided value for %s parameter '%s' " % (place, parameter)
|
||||||
|
message += "has boundaries. Do you want to inject inside? ('%s') [y/N] " % _
|
||||||
|
test = readInput(message, default="N")
|
||||||
|
if test[0] in ("y", "Y"):
|
||||||
|
testableParameters[parameter] = re.sub(regex, "\g<1>%s\g<2>" % BOUNDED_INJECTION_MARKER, testableParameters[parameter])
|
||||||
|
break
|
||||||
|
|
||||||
|
if conf.testParameter:
|
||||||
|
if not testableParameters:
|
||||||
|
paramStr = ", ".join(test for test in conf.testParameter)
|
||||||
|
|
||||||
|
if len(conf.testParameter) > 1:
|
||||||
|
warnMsg = "provided parameters '%s' " % paramStr
|
||||||
|
warnMsg += "are not inside the %s" % place
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
else:
|
||||||
|
parameter = conf.testParameter[0]
|
||||||
|
|
||||||
|
if not intersect(USER_AGENT_ALIASES + REFERER_ALIASES + HOST_ALIASES, parameter, True):
|
||||||
|
debugMsg = "provided parameter '%s' " % paramStr
|
||||||
|
debugMsg += "is not inside the %s" % place
|
||||||
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
elif len(conf.testParameter) != len(testableParameters.keys()):
|
||||||
|
for parameter in conf.testParameter:
|
||||||
|
if parameter not in testableParameters:
|
||||||
|
debugMsg = "provided parameter '%s' " % parameter
|
||||||
|
debugMsg += "is not inside the %s" % place
|
||||||
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
if testableParameters:
|
if testableParameters:
|
||||||
for parameter, value in testableParameters.items():
|
for parameter, value in testableParameters.items():
|
||||||
@@ -628,7 +685,7 @@ def paramToDict(place, parameters=None):
|
|||||||
decoded = value.decode(encoding)
|
decoded = value.decode(encoding)
|
||||||
if len(decoded) > MIN_ENCODED_LEN_CHECK and all(_ in string.printable for _ in decoded):
|
if len(decoded) > MIN_ENCODED_LEN_CHECK and all(_ in string.printable for _ in decoded):
|
||||||
warnMsg = "provided parameter '%s' " % parameter
|
warnMsg = "provided parameter '%s' " % parameter
|
||||||
warnMsg += "seems to be '%s' encoded" % encoding
|
warnMsg += "appears to be '%s' encoded" % encoding
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
@@ -676,7 +733,7 @@ def getManualDirectories():
|
|||||||
infoMsg = "retrieved the web server document root: '%s'" % directories
|
infoMsg = "retrieved the web server document root: '%s'" % directories
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
else:
|
else:
|
||||||
warnMsg = "unable to retrieve automatically the web server "
|
warnMsg = "unable to automatically retrieve the web server "
|
||||||
warnMsg += "document root"
|
warnMsg += "document root"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
@@ -715,9 +772,14 @@ def getManualDirectories():
|
|||||||
|
|
||||||
for suffix in BRUTE_DOC_ROOT_SUFFIXES:
|
for suffix in BRUTE_DOC_ROOT_SUFFIXES:
|
||||||
for target in targets:
|
for target in targets:
|
||||||
item = "%s/%s" % (prefix, suffix)
|
if not prefix.endswith("/%s" % suffix):
|
||||||
|
item = "%s/%s" % (prefix, suffix)
|
||||||
|
else:
|
||||||
|
item = prefix
|
||||||
|
|
||||||
item = item.replace(BRUTE_DOC_ROOT_TARGET_MARK, target).replace("//", '/').rstrip('/')
|
item = item.replace(BRUTE_DOC_ROOT_TARGET_MARK, target).replace("//", '/').rstrip('/')
|
||||||
directories.append(item)
|
if item not in directories:
|
||||||
|
directories.append(item)
|
||||||
|
|
||||||
if BRUTE_DOC_ROOT_TARGET_MARK not in prefix:
|
if BRUTE_DOC_ROOT_TARGET_MARK not in prefix:
|
||||||
break
|
break
|
||||||
@@ -871,7 +933,6 @@ def dataToDumpFile(dumpFile, data):
|
|||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def dataToOutFile(filename, data):
|
def dataToOutFile(filename, data):
|
||||||
retVal = None
|
retVal = None
|
||||||
|
|
||||||
@@ -879,8 +940,8 @@ def dataToOutFile(filename, data):
|
|||||||
retVal = os.path.join(conf.filePath, filePathToSafeString(filename))
|
retVal = os.path.join(conf.filePath, filePathToSafeString(filename))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(retVal, "w+b") as f:
|
with open(retVal, "w+b") as f: # has to stay as non-codecs because data is raw ASCII encoded data
|
||||||
f.write(data)
|
f.write(unicodeencode(data))
|
||||||
except IOError, ex:
|
except IOError, ex:
|
||||||
errMsg = "something went wrong while trying to write "
|
errMsg = "something went wrong while trying to write "
|
||||||
errMsg += "to the output file ('%s')" % getSafeExString(ex)
|
errMsg += "to the output file ('%s')" % getSafeExString(ex)
|
||||||
@@ -950,9 +1011,13 @@ def readInput(message, default=None, checkBatch=True):
|
|||||||
retVal = raw_input() or default
|
retVal = raw_input() or default
|
||||||
retVal = getUnicode(retVal, encoding=sys.stdin.encoding) if retVal else retVal
|
retVal = getUnicode(retVal, encoding=sys.stdin.encoding) if retVal else retVal
|
||||||
except:
|
except:
|
||||||
time.sleep(0.05) # Reference: http://www.gossamer-threads.com/lists/python/python/781893
|
try:
|
||||||
kb.prependFlag = True
|
time.sleep(0.05) # Reference: http://www.gossamer-threads.com/lists/python/python/781893
|
||||||
raise SqlmapUserQuitException
|
except:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
kb.prependFlag = True
|
||||||
|
raise SqlmapUserQuitException
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
logging._releaseLock()
|
logging._releaseLock()
|
||||||
@@ -968,7 +1033,12 @@ def randomRange(start=0, stop=1000, seed=None):
|
|||||||
423
|
423
|
||||||
"""
|
"""
|
||||||
|
|
||||||
randint = random.WichmannHill(seed).randint if seed is not None else random.randint
|
if seed is not None:
|
||||||
|
_ = getCurrentThreadData().random
|
||||||
|
_.seed(seed)
|
||||||
|
randint = _.randint
|
||||||
|
else:
|
||||||
|
randint = random.randint
|
||||||
|
|
||||||
return int(randint(start, stop))
|
return int(randint(start, stop))
|
||||||
|
|
||||||
@@ -981,7 +1051,12 @@ def randomInt(length=4, seed=None):
|
|||||||
874254
|
874254
|
||||||
"""
|
"""
|
||||||
|
|
||||||
choice = random.WichmannHill(seed).choice if seed is not None else random.choice
|
if seed is not None:
|
||||||
|
_ = getCurrentThreadData().random
|
||||||
|
_.seed(seed)
|
||||||
|
choice = _.choice
|
||||||
|
else:
|
||||||
|
choice = random.choice
|
||||||
|
|
||||||
return int("".join(choice(string.digits if _ != 0 else string.digits.replace('0', '')) for _ in xrange(0, length)))
|
return int("".join(choice(string.digits if _ != 0 else string.digits.replace('0', '')) for _ in xrange(0, length)))
|
||||||
|
|
||||||
@@ -994,7 +1069,12 @@ def randomStr(length=4, lowercase=False, alphabet=None, seed=None):
|
|||||||
'RNvnAv'
|
'RNvnAv'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
choice = random.WichmannHill(seed).choice if seed is not None else random.choice
|
if seed is not None:
|
||||||
|
_ = getCurrentThreadData().random
|
||||||
|
_.seed(seed)
|
||||||
|
choice = _.choice
|
||||||
|
else:
|
||||||
|
choice = random.choice
|
||||||
|
|
||||||
if alphabet:
|
if alphabet:
|
||||||
retVal = "".join(choice(alphabet) for _ in xrange(0, length))
|
retVal = "".join(choice(alphabet) for _ in xrange(0, length))
|
||||||
@@ -1053,10 +1133,15 @@ def banner():
|
|||||||
This function prints sqlmap banner with its version
|
This function prints sqlmap banner with its version
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_ = BANNER
|
if not any(_ in sys.argv for _ in ("--version", "--pickled-options")):
|
||||||
if not getattr(LOGGER_HANDLER, "is_tty", False):
|
_ = BANNER
|
||||||
_ = re.sub("\033.+?m", "", _)
|
|
||||||
dataToStdout(_, forceOutput=True)
|
if not getattr(LOGGER_HANDLER, "is_tty", False) or "--disable-coloring" in sys.argv:
|
||||||
|
_ = re.sub("\033.+?m", "", _)
|
||||||
|
elif IS_WIN:
|
||||||
|
coloramainit()
|
||||||
|
|
||||||
|
dataToStdout(_, forceOutput=True)
|
||||||
|
|
||||||
def parsePasswordHash(password):
|
def parsePasswordHash(password):
|
||||||
"""
|
"""
|
||||||
@@ -1115,7 +1200,7 @@ def setPaths():
|
|||||||
paths.SQLMAP_XML_PAYLOADS_PATH = os.path.join(paths.SQLMAP_XML_PATH, "payloads")
|
paths.SQLMAP_XML_PAYLOADS_PATH = os.path.join(paths.SQLMAP_XML_PATH, "payloads")
|
||||||
|
|
||||||
_ = os.path.join(os.path.expandvars(os.path.expanduser("~")), ".sqlmap")
|
_ = os.path.join(os.path.expandvars(os.path.expanduser("~")), ".sqlmap")
|
||||||
paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), encoding=sys.getfilesystemencoding())
|
paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
|
||||||
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
||||||
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
|
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
|
||||||
|
|
||||||
@@ -1302,8 +1387,8 @@ def parseTargetUrl():
|
|||||||
except UnicodeError:
|
except UnicodeError:
|
||||||
_ = None
|
_ = None
|
||||||
|
|
||||||
if any((_ is None, re.search(r'\s', conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'))):
|
if any((_ is None, re.search(r'\s', conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'), '\n' in originalUrl)):
|
||||||
errMsg = "invalid target URL"
|
errMsg = "invalid target URL ('%s')" % originalUrl
|
||||||
raise SqlmapSyntaxException(errMsg)
|
raise SqlmapSyntaxException(errMsg)
|
||||||
|
|
||||||
if len(hostnamePort) == 2:
|
if len(hostnamePort) == 2:
|
||||||
@@ -1317,12 +1402,19 @@ def parseTargetUrl():
|
|||||||
else:
|
else:
|
||||||
conf.port = 80
|
conf.port = 80
|
||||||
|
|
||||||
if urlSplit.query:
|
if conf.port < 0 or conf.port > 65535:
|
||||||
conf.parameters[PLACE.GET] = urldecode(urlSplit.query) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query
|
errMsg = "invalid target URL's 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:%d%s" % (conf.scheme, ("[%s]" % conf.hostname) if conf.ipv6 else conf.hostname, conf.port, conf.path))
|
||||||
conf.url = conf.url.replace(URI_QUESTION_MARKER, '?')
|
conf.url = conf.url.replace(URI_QUESTION_MARKER, '?')
|
||||||
|
|
||||||
|
if urlSplit.query:
|
||||||
|
if '=' not in urlSplit.query:
|
||||||
|
conf.url = "%s?%s" % (conf.url, getUnicode(urlSplit.query))
|
||||||
|
else:
|
||||||
|
conf.parameters[PLACE.GET] = urldecode(urlSplit.query) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query
|
||||||
|
|
||||||
if not conf.referer and (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3):
|
if not conf.referer and (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3):
|
||||||
debugMsg = "setting the HTTP Referer header to the target URL"
|
debugMsg = "setting the HTTP Referer header to the target URL"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
@@ -1452,7 +1544,7 @@ def parseFilePaths(page):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if page:
|
if page:
|
||||||
for regex in (r" in <b>(?P<result>.*?)</b> on line", r"(?:>|\s)(?P<result>[A-Za-z]:[\\/][\w.\\/]*)", r"(?:>|\s)(?P<result>/\w[/\w.]+)"):
|
for regex in FILE_PATH_REGEXES:
|
||||||
for match in re.finditer(regex, page):
|
for match in re.finditer(regex, page):
|
||||||
absFilePath = match.group("result").strip()
|
absFilePath = match.group("result").strip()
|
||||||
page = page.replace(absFilePath, "")
|
page = page.replace(absFilePath, "")
|
||||||
@@ -1828,7 +1920,7 @@ def parseXmlFile(xmlFile, handler):
|
|||||||
with contextlib.closing(StringIO(readCachedFileContent(xmlFile))) as stream:
|
with contextlib.closing(StringIO(readCachedFileContent(xmlFile))) as stream:
|
||||||
parse(stream, handler)
|
parse(stream, handler)
|
||||||
except (SAXParseException, UnicodeError), ex:
|
except (SAXParseException, UnicodeError), ex:
|
||||||
errMsg = "something seems to be wrong with "
|
errMsg = "something appears to be wrong with "
|
||||||
errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex))
|
errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex))
|
||||||
errMsg += "sure that you haven't made any changes to it"
|
errMsg += "sure that you haven't made any changes to it"
|
||||||
raise SqlmapInstallationException, errMsg
|
raise SqlmapInstallationException, errMsg
|
||||||
@@ -1886,8 +1978,8 @@ def readCachedFileContent(filename, mode='rb'):
|
|||||||
if filename not in kb.cache.content:
|
if filename not in kb.cache.content:
|
||||||
checkFile(filename)
|
checkFile(filename)
|
||||||
try:
|
try:
|
||||||
with openFile(filename, mode) as f:
|
with openFile(filename, mode) as f:
|
||||||
kb.cache.content[filename] = f.read()
|
kb.cache.content[filename] = f.read()
|
||||||
except (IOError, OSError, MemoryError), ex:
|
except (IOError, OSError, MemoryError), ex:
|
||||||
errMsg = "something went wrong while trying "
|
errMsg = "something went wrong while trying "
|
||||||
errMsg += "to read the content of file '%s' ('%s')" % (filename, getSafeExString(ex))
|
errMsg += "to read the content of file '%s' ('%s')" % (filename, getSafeExString(ex))
|
||||||
@@ -2783,7 +2875,7 @@ def setOptimize():
|
|||||||
conf.nullConnection = not any((conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor))
|
conf.nullConnection = not any((conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor))
|
||||||
|
|
||||||
if not conf.nullConnection:
|
if not conf.nullConnection:
|
||||||
debugMsg = "turning off --null-connection switch used indirectly by switch -o"
|
debugMsg = "turning off switch '--null-connection' used indirectly by switch '-o'"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
def initTechnique(technique=None):
|
def initTechnique(technique=None):
|
||||||
@@ -2971,7 +3063,10 @@ def decodeIntToUnicode(value):
|
|||||||
_ = "0%s" % _
|
_ = "0%s" % _
|
||||||
raw = hexdecode(_)
|
raw = hexdecode(_)
|
||||||
|
|
||||||
if Backend.isDbms(DBMS.MSSQL):
|
if Backend.isDbms(DBMS.MYSQL):
|
||||||
|
# https://github.com/sqlmapproject/sqlmap/issues/1531
|
||||||
|
retVal = getUnicode(raw, conf.charset or UNICODE_ENCODING)
|
||||||
|
elif Backend.isDbms(DBMS.MSSQL):
|
||||||
retVal = getUnicode(raw, "UTF-16-BE")
|
retVal = getUnicode(raw, "UTF-16-BE")
|
||||||
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE):
|
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE):
|
||||||
retVal = unichr(value)
|
retVal = unichr(value)
|
||||||
@@ -3147,14 +3242,6 @@ def intersect(valueA, valueB, lowerCase=False):
|
|||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
def cpuThrottle(value):
|
|
||||||
"""
|
|
||||||
Does a CPU throttling for lesser CPU consumption
|
|
||||||
"""
|
|
||||||
|
|
||||||
delay = 0.00001 * (value ** 2)
|
|
||||||
time.sleep(delay)
|
|
||||||
|
|
||||||
def removeReflectiveValues(content, payload, suppressWarning=False):
|
def removeReflectiveValues(content, payload, suppressWarning=False):
|
||||||
"""
|
"""
|
||||||
Neutralizes reflective values in a given content based on a payload
|
Neutralizes reflective values in a given content based on a payload
|
||||||
@@ -3258,7 +3345,7 @@ def safeSQLIdentificatorNaming(name, isTable=False):
|
|||||||
retVal = "\"%s\"" % retVal.strip("\"")
|
retVal = "\"%s\"" % retVal.strip("\"")
|
||||||
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
|
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
|
||||||
retVal = "\"%s\"" % retVal.strip("\"").upper()
|
retVal = "\"%s\"" % retVal.strip("\"").upper()
|
||||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL,) and not re.match(r"\A\w+\Z", retVal, re.U):
|
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL,) and ((retVal or " ")[0].isdigit() or not re.match(r"\A\w+\Z", retVal, re.U)):
|
||||||
retVal = "[%s]" % retVal.strip("[]")
|
retVal = "[%s]" % retVal.strip("[]")
|
||||||
|
|
||||||
if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal):
|
if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal):
|
||||||
@@ -3897,7 +3984,7 @@ def resetCookieJar(cookieJar):
|
|||||||
|
|
||||||
content = readCachedFileContent(conf.loadCookies)
|
content = readCachedFileContent(conf.loadCookies)
|
||||||
lines = filter(None, (line.strip() for line in content.split("\n") if not line.startswith('#')))
|
lines = filter(None, (line.strip() for line in content.split("\n") if not line.startswith('#')))
|
||||||
handle, filename = tempfile.mkstemp(prefix="sqlmapcj-")
|
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.COOKIE_JAR)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
|
|
||||||
# Reference: http://www.hashbangcode.com/blog/netscape-http-cooke-file-parser-php-584.html
|
# Reference: http://www.hashbangcode.com/blog/netscape-http-cooke-file-parser-php-584.html
|
||||||
|
|||||||
+1
-2
@@ -11,7 +11,6 @@ import pickle
|
|||||||
import re
|
import re
|
||||||
import StringIO
|
import StringIO
|
||||||
import sys
|
import sys
|
||||||
import types
|
|
||||||
|
|
||||||
from lib.core.settings import IS_WIN
|
from lib.core.settings import IS_WIN
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
@@ -161,7 +160,7 @@ def htmlunescape(value):
|
|||||||
codes = (('<', '<'), ('>', '>'), ('"', '"'), (' ', ' '), ('&', '&'))
|
codes = (('<', '<'), ('>', '>'), ('"', '"'), (' ', ' '), ('&', '&'))
|
||||||
retVal = reduce(lambda x, y: x.replace(y[0], y[1]), codes, retVal)
|
retVal = reduce(lambda x, y: x.replace(y[0], y[1]), codes, retVal)
|
||||||
try:
|
try:
|
||||||
retVal = re.sub(r"&#x([^;]+);", lambda match: unichr(int(match.group(1), 16)), retVal)
|
retVal = re.sub(r"&#x([^ ;]+);", lambda match: unichr(int(match.group(1), 16)), retVal)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
return retVal
|
return retVal
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ See the file 'doc/COPYING' for copying permission
|
|||||||
import copy
|
import copy
|
||||||
import types
|
import types
|
||||||
|
|
||||||
from lib.core.exception import SqlmapDataException
|
|
||||||
|
|
||||||
class AttribDict(dict):
|
class AttribDict(dict):
|
||||||
"""
|
"""
|
||||||
This class defines the sqlmap object, inheriting from Python data
|
This class defines the sqlmap object, inheriting from Python data
|
||||||
@@ -43,7 +41,7 @@ class AttribDict(dict):
|
|||||||
try:
|
try:
|
||||||
return self.__getitem__(item)
|
return self.__getitem__(item)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise SqlmapDataException("unable to access item '%s'" % item)
|
raise AttributeError("unable to access item '%s'" % item)
|
||||||
|
|
||||||
def __setattr__(self, item, value):
|
def __setattr__(self, item, value):
|
||||||
"""
|
"""
|
||||||
@@ -93,6 +91,7 @@ class InjectionDict(AttribDict):
|
|||||||
self.prefix = None
|
self.prefix = None
|
||||||
self.suffix = None
|
self.suffix = None
|
||||||
self.clause = None
|
self.clause = None
|
||||||
|
self.notes = [] # Note: https://github.com/sqlmapproject/sqlmap/issues/1888
|
||||||
|
|
||||||
# data is a dict with various stype, each which is a dict with
|
# data is a dict with various stype, each which is a dict with
|
||||||
# all the information specific for that stype
|
# all the information specific for that stype
|
||||||
|
|||||||
@@ -15,10 +15,13 @@ def cachedmethod(f, cache={}):
|
|||||||
def _(*args, **kwargs):
|
def _(*args, **kwargs):
|
||||||
try:
|
try:
|
||||||
key = (f, tuple(args), frozenset(kwargs.items()))
|
key = (f, tuple(args), frozenset(kwargs.items()))
|
||||||
|
if key not in cache:
|
||||||
|
cache[key] = f(*args, **kwargs)
|
||||||
except:
|
except:
|
||||||
key = "".join(str(_) for _ in (f, args, kwargs))
|
key = "".join(str(_) for _ in (f, args, kwargs))
|
||||||
if key not in cache:
|
if key not in cache:
|
||||||
cache[key] = f(*args, **kwargs)
|
cache[key] = f(*args, **kwargs)
|
||||||
|
|
||||||
return cache[key]
|
return cache[key]
|
||||||
|
|
||||||
return _
|
return _
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ _defaults = {
|
|||||||
"csvDel": ",",
|
"csvDel": ",",
|
||||||
"timeSec": 5,
|
"timeSec": 5,
|
||||||
"googlePage": 1,
|
"googlePage": 1,
|
||||||
"cpuThrottle": 5,
|
|
||||||
"verbose": 1,
|
"verbose": 1,
|
||||||
"delay": 0,
|
"delay": 0,
|
||||||
"timeout": 30,
|
"timeout": 30,
|
||||||
|
|||||||
+2
-2
@@ -234,6 +234,6 @@ DUMP_DATA_PREPROCESS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_DOC_ROOTS = {
|
DEFAULT_DOC_ROOTS = {
|
||||||
OS.WINDOWS: ("C:/xampp/htdocs/", "C:/Inetpub/wwwroot/"),
|
OS.WINDOWS: ("C:/xampp/htdocs/", "C:/wamp/www/", "C:/Inetpub/wwwroot/"),
|
||||||
OS.LINUX: ("/var/www/", "/var/www/html", "/usr/local/apache2/htdocs", "/var/www/nginx-default") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout
|
OS.LINUX: ("/var/www/", "/var/www/html", "/usr/local/apache2/htdocs", "/var/www/nginx-default", "/srv/www") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-1
@@ -9,6 +9,7 @@ import cgi
|
|||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
@@ -449,8 +450,23 @@ class Dump(object):
|
|||||||
dumpFileName = os.path.join(dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(unicodeencode(table)).hexdigest()[:8], conf.dumpFormat.lower()))
|
dumpFileName = os.path.join(dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(unicodeencode(table)).hexdigest()[:8], conf.dumpFormat.lower()))
|
||||||
else:
|
else:
|
||||||
dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower()))
|
dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower()))
|
||||||
|
else:
|
||||||
|
appendToFile = any((conf.limitStart, conf.limitStop))
|
||||||
|
|
||||||
|
if not appendToFile:
|
||||||
|
count = 1
|
||||||
|
while True:
|
||||||
|
candidate = "%s.%d" % (dumpFileName, count)
|
||||||
|
if not checkFile(candidate, False):
|
||||||
|
try:
|
||||||
|
shutil.copyfile(dumpFileName, candidate)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
count += 1
|
||||||
|
|
||||||
appendToFile = any((conf.limitStart, conf.limitStop)) and checkFile(dumpFileName, False)
|
|
||||||
dumpFP = openFile(dumpFileName, "wb" if not appendToFile else "ab", buffering=DUMP_FILE_BUFFER_SIZE)
|
dumpFP = openFile(dumpFileName, "wb" if not appendToFile else "ab", buffering=DUMP_FILE_BUFFER_SIZE)
|
||||||
|
|
||||||
count = int(tableValues["__infos__"]["count"])
|
count = int(tableValues["__infos__"]["count"])
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ class OPTION_TYPE:
|
|||||||
|
|
||||||
class HASHDB_KEYS:
|
class HASHDB_KEYS:
|
||||||
DBMS = "DBMS"
|
DBMS = "DBMS"
|
||||||
|
DBMS_FORK = "DBMS_FORK"
|
||||||
CHECK_WAF_RESULT = "CHECK_WAF_RESULT"
|
CHECK_WAF_RESULT = "CHECK_WAF_RESULT"
|
||||||
CONF_TMP_PATH = "CONF_TMP_PATH"
|
CONF_TMP_PATH = "CONF_TMP_PATH"
|
||||||
KB_ABS_FILE_PATHS = "KB_ABS_FILE_PATHS"
|
KB_ABS_FILE_PATHS = "KB_ABS_FILE_PATHS"
|
||||||
@@ -351,3 +352,15 @@ class AUTOCOMPLETE_TYPE:
|
|||||||
SQL = 0
|
SQL = 0
|
||||||
OS = 1
|
OS = 1
|
||||||
SQLMAP = 2
|
SQLMAP = 2
|
||||||
|
|
||||||
|
class NOTE:
|
||||||
|
FALSE_POSITIVE_OR_UNEXPLOITABLE = "false positive or unexploitable"
|
||||||
|
|
||||||
|
class MKSTEMP_PREFIX:
|
||||||
|
HASHES = "sqlmaphashes-"
|
||||||
|
CRAWLER = "sqlmapcrawler-"
|
||||||
|
IPC = "sqlmapipc-"
|
||||||
|
TESTING = "sqlmaptesting-"
|
||||||
|
RESULTS = "sqlmapresults-"
|
||||||
|
COOKIE_JAR = "sqlmapcookiejar-"
|
||||||
|
BIG_ARRAY = "sqlmapbigarray-"
|
||||||
|
|||||||
+62
-25
@@ -127,12 +127,14 @@ from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX
|
|||||||
from lib.core.settings import SUPPORTED_DBMS
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
from lib.core.settings import SUPPORTED_OS
|
from lib.core.settings import SUPPORTED_OS
|
||||||
from lib.core.settings import TIME_DELAY_CANDIDATES
|
from lib.core.settings import TIME_DELAY_CANDIDATES
|
||||||
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
from lib.core.settings import UNION_CHAR_REGEX
|
from lib.core.settings import UNION_CHAR_REGEX
|
||||||
from lib.core.settings import UNKNOWN_DBMS_VERSION
|
from lib.core.settings import UNKNOWN_DBMS_VERSION
|
||||||
from lib.core.settings import URI_INJECTABLE_REGEX
|
from lib.core.settings import URI_INJECTABLE_REGEX
|
||||||
from lib.core.settings import VERSION_STRING
|
from lib.core.settings import VERSION_STRING
|
||||||
from lib.core.settings import WEBSCARAB_SPLITTER
|
from lib.core.settings import WEBSCARAB_SPLITTER
|
||||||
from lib.core.threads import getCurrentThreadData
|
from lib.core.threads import getCurrentThreadData
|
||||||
|
from lib.core.threads import setDaemon
|
||||||
from lib.core.update import update
|
from lib.core.update import update
|
||||||
from lib.parse.configfile import configFileParser
|
from lib.parse.configfile import configFileParser
|
||||||
from lib.parse.payloads import loadBoundaries
|
from lib.parse.payloads import loadBoundaries
|
||||||
@@ -151,7 +153,6 @@ from lib.utils.crawler import crawl
|
|||||||
from lib.utils.deps import checkDependencies
|
from lib.utils.deps import checkDependencies
|
||||||
from lib.utils.search import search
|
from lib.utils.search import search
|
||||||
from lib.utils.purge import purge
|
from lib.utils.purge import purge
|
||||||
from thirdparty.colorama.initialise import init as coloramainit
|
|
||||||
from thirdparty.keepalive import keepalive
|
from thirdparty.keepalive import keepalive
|
||||||
from thirdparty.oset.pyoset import oset
|
from thirdparty.oset.pyoset import oset
|
||||||
from thirdparty.socks import socks
|
from thirdparty.socks import socks
|
||||||
@@ -385,7 +386,7 @@ def _loadQueries():
|
|||||||
try:
|
try:
|
||||||
tree.parse(paths.QUERIES_XML)
|
tree.parse(paths.QUERIES_XML)
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
errMsg = "something seems to be wrong with "
|
errMsg = "something appears to be wrong with "
|
||||||
errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex))
|
errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex))
|
||||||
errMsg += "sure that you haven't made any changes to it"
|
errMsg += "sure that you haven't made any changes to it"
|
||||||
raise SqlmapInstallationException, errMsg
|
raise SqlmapInstallationException, errMsg
|
||||||
@@ -913,9 +914,9 @@ def _setTamperingFunctions():
|
|||||||
sys.path.insert(0, dirname)
|
sys.path.insert(0, dirname)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
module = __import__(filename[:-3].encode(sys.getfilesystemencoding()))
|
module = __import__(filename[:-3].encode(sys.getfilesystemencoding() or UNICODE_ENCODING))
|
||||||
except (ImportError, SyntaxError), msg:
|
except (ImportError, SyntaxError), ex:
|
||||||
raise SqlmapSyntaxException("cannot import tamper script '%s' (%s)" % (filename[:-3], msg))
|
raise SqlmapSyntaxException("cannot import tamper script '%s' (%s)" % (filename[:-3], getSafeExString(ex)))
|
||||||
|
|
||||||
priority = PRIORITY.NORMAL if not hasattr(module, '__priority__') else module.__priority__
|
priority = PRIORITY.NORMAL if not hasattr(module, '__priority__') else module.__priority__
|
||||||
|
|
||||||
@@ -926,7 +927,7 @@ def _setTamperingFunctions():
|
|||||||
function.func_name = module.__name__
|
function.func_name = module.__name__
|
||||||
|
|
||||||
if check_priority and priority > last_priority:
|
if check_priority and priority > last_priority:
|
||||||
message = "it seems that you might have mixed "
|
message = "it appears that you might have mixed "
|
||||||
message += "the order of tamper scripts. "
|
message += "the order of tamper scripts. "
|
||||||
message += "Do you want to auto resolve this? [Y/n/q] "
|
message += "Do you want to auto resolve this? [Y/n/q] "
|
||||||
test = readInput(message, default="Y")
|
test = readInput(message, default="Y")
|
||||||
@@ -998,6 +999,8 @@ def _setWafFunctions():
|
|||||||
else:
|
else:
|
||||||
kb.wafFunctions.append((_["detect"], _.get("__product__", filename[:-3])))
|
kb.wafFunctions.append((_["detect"], _.get("__product__", filename[:-3])))
|
||||||
|
|
||||||
|
kb.wafFunctions = sorted(kb.wafFunctions, key=lambda _: "generic" in _[1].lower())
|
||||||
|
|
||||||
def _setThreads():
|
def _setThreads():
|
||||||
if not isinstance(conf.threads, int) or conf.threads <= 0:
|
if not isinstance(conf.threads, int) or conf.threads <= 0:
|
||||||
conf.threads = 1
|
conf.threads = 1
|
||||||
@@ -1064,6 +1067,7 @@ def _setSocketPreConnect():
|
|||||||
socket.socket.connect = connect
|
socket.socket.connect = connect
|
||||||
|
|
||||||
thread = threading.Thread(target=_)
|
thread = threading.Thread(target=_)
|
||||||
|
setDaemon(thread)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
def _setHTTPHandlers():
|
def _setHTTPHandlers():
|
||||||
@@ -1545,18 +1549,36 @@ def _createTemporaryDirectory():
|
|||||||
Creates temporary directory for this run.
|
Creates temporary directory for this run.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
if conf.tmpDir:
|
||||||
if not os.path.isdir(tempfile.gettempdir()):
|
try:
|
||||||
os.makedirs(tempfile.gettempdir())
|
if not os.path.isdir(conf.tmpDir):
|
||||||
except IOError, ex:
|
os.makedirs(conf.tmpDir)
|
||||||
errMsg = "there has been a problem while accessing "
|
|
||||||
errMsg += "system's temporary directory location(s) ('%s'). Please " % getSafeExString(ex)
|
|
||||||
errMsg += "make sure that there is enough disk space left. If problem persists, "
|
|
||||||
errMsg += "try to set environment variable 'TEMP' to a location "
|
|
||||||
errMsg += "writeable by the current user"
|
|
||||||
raise SqlmapSystemException, errMsg
|
|
||||||
|
|
||||||
if "sqlmap" not in (tempfile.tempdir or ""):
|
_ = os.path.join(conf.tmpDir, randomStr())
|
||||||
|
open(_, "w+b").close()
|
||||||
|
os.remove(_)
|
||||||
|
|
||||||
|
tempfile.tempdir = conf.tmpDir
|
||||||
|
|
||||||
|
warnMsg = "using '%s' as the temporary directory" % conf.tmpDir
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
except (OSError, IOError), ex:
|
||||||
|
errMsg = "there has been a problem while accessing "
|
||||||
|
errMsg += "temporary directory location(s) ('%s')" % getSafeExString(ex)
|
||||||
|
raise SqlmapSystemException, errMsg
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if not os.path.isdir(tempfile.gettempdir()):
|
||||||
|
os.makedirs(tempfile.gettempdir())
|
||||||
|
except IOError, ex:
|
||||||
|
errMsg = "there has been a problem while accessing "
|
||||||
|
errMsg += "system's temporary directory location(s) ('%s'). Please " % getSafeExString(ex)
|
||||||
|
errMsg += "make sure that there is enough disk space left. If problem persists, "
|
||||||
|
errMsg += "try to set environment variable 'TEMP' to a location "
|
||||||
|
errMsg += "writeable by the current user"
|
||||||
|
raise SqlmapSystemException, errMsg
|
||||||
|
|
||||||
|
if "sqlmap" not in (tempfile.tempdir or "") or conf.tmpDir and tempfile.tempdir == conf.tmpDir:
|
||||||
tempfile.tempdir = tempfile.mkdtemp(prefix="sqlmap", suffix=str(os.getpid()))
|
tempfile.tempdir = tempfile.mkdtemp(prefix="sqlmap", suffix=str(os.getpid()))
|
||||||
|
|
||||||
kb.tempDir = tempfile.tempdir
|
kb.tempDir = tempfile.tempdir
|
||||||
@@ -1590,6 +1612,9 @@ def _cleanupOptions():
|
|||||||
else:
|
else:
|
||||||
conf.testParameter = []
|
conf.testParameter = []
|
||||||
|
|
||||||
|
if conf.agent:
|
||||||
|
conf.agent = re.sub(r"[\r\n]", "", conf.agent)
|
||||||
|
|
||||||
if conf.user:
|
if conf.user:
|
||||||
conf.user = conf.user.replace(" ", "")
|
conf.user = conf.user.replace(" ", "")
|
||||||
|
|
||||||
@@ -1654,10 +1679,20 @@ def _cleanupOptions():
|
|||||||
conf.testFilter = conf.testFilter.strip('*+')
|
conf.testFilter = conf.testFilter.strip('*+')
|
||||||
conf.testFilter = re.sub(r"([^.])([*+])", "\g<1>.\g<2>", conf.testFilter)
|
conf.testFilter = re.sub(r"([^.])([*+])", "\g<1>.\g<2>", conf.testFilter)
|
||||||
|
|
||||||
|
try:
|
||||||
|
re.compile(conf.testFilter)
|
||||||
|
except re.error:
|
||||||
|
conf.testFilter = re.escape(conf.testFilter)
|
||||||
|
|
||||||
if conf.testSkip:
|
if conf.testSkip:
|
||||||
conf.testSkip = conf.testSkip.strip('*+')
|
conf.testSkip = conf.testSkip.strip('*+')
|
||||||
conf.testSkip = re.sub(r"([^.])([*+])", "\g<1>.\g<2>", conf.testSkip)
|
conf.testSkip = re.sub(r"([^.])([*+])", "\g<1>.\g<2>", conf.testSkip)
|
||||||
|
|
||||||
|
try:
|
||||||
|
re.compile(conf.testSkip)
|
||||||
|
except re.error:
|
||||||
|
conf.testSkip = re.escape(conf.testSkip)
|
||||||
|
|
||||||
if "timeSec" not in kb.explicitSettings:
|
if "timeSec" not in kb.explicitSettings:
|
||||||
if conf.tor:
|
if conf.tor:
|
||||||
conf.timeSec = 2 * conf.timeSec
|
conf.timeSec = 2 * conf.timeSec
|
||||||
@@ -1799,6 +1834,8 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.cache.regex = {}
|
kb.cache.regex = {}
|
||||||
kb.cache.stdev = {}
|
kb.cache.stdev = {}
|
||||||
|
|
||||||
|
kb.captchaDetected = None
|
||||||
|
|
||||||
kb.chars = AttribDict()
|
kb.chars = AttribDict()
|
||||||
kb.chars.delimiter = randomStr(length=6, lowercase=True)
|
kb.chars.delimiter = randomStr(length=6, lowercase=True)
|
||||||
kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR)
|
kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR)
|
||||||
@@ -1807,6 +1844,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
|
|
||||||
kb.columnExistsChoice = None
|
kb.columnExistsChoice = None
|
||||||
kb.commonOutputs = None
|
kb.commonOutputs = None
|
||||||
|
kb.cookieEncodeChoice = None
|
||||||
kb.counters = {}
|
kb.counters = {}
|
||||||
kb.data = AttribDict()
|
kb.data = AttribDict()
|
||||||
kb.dataOutputFlag = False
|
kb.dataOutputFlag = False
|
||||||
@@ -1829,6 +1867,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.extendTests = None
|
kb.extendTests = None
|
||||||
kb.errorChunkLength = None
|
kb.errorChunkLength = None
|
||||||
kb.errorIsNone = True
|
kb.errorIsNone = True
|
||||||
|
kb.falsePositives = []
|
||||||
kb.fileReadMode = False
|
kb.fileReadMode = False
|
||||||
kb.followSitemapRecursion = None
|
kb.followSitemapRecursion = None
|
||||||
kb.forcedDbms = None
|
kb.forcedDbms = None
|
||||||
@@ -1838,6 +1877,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.headersFp = {}
|
kb.headersFp = {}
|
||||||
kb.heuristicDbms = None
|
kb.heuristicDbms = None
|
||||||
kb.heuristicMode = False
|
kb.heuristicMode = False
|
||||||
|
kb.heuristicPage = False
|
||||||
kb.heuristicTest = None
|
kb.heuristicTest = None
|
||||||
kb.hintValue = None
|
kb.hintValue = None
|
||||||
kb.htmlFp = []
|
kb.htmlFp = []
|
||||||
@@ -1896,6 +1936,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS: 0, REFLECTIVE_COUNTER.HIT: 0}
|
kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS: 0, REFLECTIVE_COUNTER.HIT: 0}
|
||||||
kb.requestCounter = 0
|
kb.requestCounter = 0
|
||||||
kb.resendPostOnRedirect = None
|
kb.resendPostOnRedirect = None
|
||||||
|
kb.resolutionDbms = None
|
||||||
kb.responseTimes = {}
|
kb.responseTimes = {}
|
||||||
kb.responseTimeMode = None
|
kb.responseTimeMode = None
|
||||||
kb.responseTimePayload = None
|
kb.responseTimePayload = None
|
||||||
@@ -1903,6 +1944,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.safeCharEncode = False
|
kb.safeCharEncode = False
|
||||||
kb.safeReq = AttribDict()
|
kb.safeReq = AttribDict()
|
||||||
kb.singleLogFlags = set()
|
kb.singleLogFlags = set()
|
||||||
|
kb.skipSeqMatcher = False
|
||||||
kb.reduceTests = None
|
kb.reduceTests = None
|
||||||
kb.tlsSNI = {}
|
kb.tlsSNI = {}
|
||||||
kb.stickyDBMS = False
|
kb.stickyDBMS = False
|
||||||
@@ -1910,6 +1952,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||||||
kb.storeCrawlingChoice = None
|
kb.storeCrawlingChoice = None
|
||||||
kb.storeHashesChoice = None
|
kb.storeHashesChoice = None
|
||||||
kb.suppressResumeInfo = False
|
kb.suppressResumeInfo = False
|
||||||
|
kb.tableFrom = None
|
||||||
kb.technique = None
|
kb.technique = None
|
||||||
kb.tempDir = None
|
kb.tempDir = None
|
||||||
kb.testMode = False
|
kb.testMode = False
|
||||||
@@ -2298,7 +2341,7 @@ def _checkTor():
|
|||||||
page = None
|
page = None
|
||||||
|
|
||||||
if not page or 'Congratulations' not in page:
|
if not page or 'Congratulations' not in page:
|
||||||
errMsg = "it seems that Tor is not properly set. Please try using options '--tor-type' and/or '--tor-port'"
|
errMsg = "it appears that Tor is not properly set. Please try using options '--tor-type' and/or '--tor-port'"
|
||||||
raise SqlmapConnectionException(errMsg)
|
raise SqlmapConnectionException(errMsg)
|
||||||
else:
|
else:
|
||||||
infoMsg = "Tor is properly being used"
|
infoMsg = "Tor is properly being used"
|
||||||
@@ -2331,10 +2374,6 @@ def _basicOptionValidation():
|
|||||||
errMsg = "value for option '--first' (firstChar) must be smaller than or equal to value for --last (lastChar) option"
|
errMsg = "value for option '--first' (firstChar) must be smaller than or equal to value for --last (lastChar) option"
|
||||||
raise SqlmapSyntaxException(errMsg)
|
raise SqlmapSyntaxException(errMsg)
|
||||||
|
|
||||||
if isinstance(conf.cpuThrottle, int) and (conf.cpuThrottle > 100 or conf.cpuThrottle < 0):
|
|
||||||
errMsg = "value for option '--cpu-throttle' (cpuThrottle) must be in range [0,100]"
|
|
||||||
raise SqlmapSyntaxException(errMsg)
|
|
||||||
|
|
||||||
if conf.textOnly and conf.nullConnection:
|
if conf.textOnly and conf.nullConnection:
|
||||||
errMsg = "switch '--text-only' is incompatible with switch '--null-connection'"
|
errMsg = "switch '--text-only' is incompatible with switch '--null-connection'"
|
||||||
raise SqlmapSyntaxException(errMsg)
|
raise SqlmapSyntaxException(errMsg)
|
||||||
@@ -2534,11 +2573,9 @@ def _resolveCrossReferences():
|
|||||||
lib.request.connect.setHTTPHandlers = _setHTTPHandlers
|
lib.request.connect.setHTTPHandlers = _setHTTPHandlers
|
||||||
lib.utils.search.setHTTPHandlers = _setHTTPHandlers
|
lib.utils.search.setHTTPHandlers = _setHTTPHandlers
|
||||||
lib.controller.checks.setVerbosity = setVerbosity
|
lib.controller.checks.setVerbosity = setVerbosity
|
||||||
|
lib.controller.checks.setWafFunctions = _setWafFunctions
|
||||||
|
|
||||||
def initOptions(inputOptions=AttribDict(), overrideOptions=False):
|
def initOptions(inputOptions=AttribDict(), overrideOptions=False):
|
||||||
if IS_WIN:
|
|
||||||
coloramainit()
|
|
||||||
|
|
||||||
_setConfAttributes()
|
_setConfAttributes()
|
||||||
_setKnowledgeBaseAttributes()
|
_setKnowledgeBaseAttributes()
|
||||||
_mergeOptions(inputOptions, overrideOptions)
|
_mergeOptions(inputOptions, overrideOptions)
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ optDict = {
|
|||||||
"tbl": "string",
|
"tbl": "string",
|
||||||
"col": "string",
|
"col": "string",
|
||||||
"excludeCol": "string",
|
"excludeCol": "string",
|
||||||
|
"pivotColumn": "string",
|
||||||
"dumpWhere": "string",
|
"dumpWhere": "string",
|
||||||
"user": "string",
|
"user": "string",
|
||||||
"excludeSysDbs": "boolean",
|
"excludeSysDbs": "boolean",
|
||||||
@@ -189,6 +190,7 @@ optDict = {
|
|||||||
#"xmlFile": "string",
|
#"xmlFile": "string",
|
||||||
"trafficFile": "string",
|
"trafficFile": "string",
|
||||||
"batch": "boolean",
|
"batch": "boolean",
|
||||||
|
"binaryFields": "string",
|
||||||
"charset": "string",
|
"charset": "string",
|
||||||
"crawlDepth": "integer",
|
"crawlDepth": "integer",
|
||||||
"crawlExclude": "string",
|
"crawlExclude": "string",
|
||||||
@@ -201,7 +203,6 @@ optDict = {
|
|||||||
"hexConvert": "boolean",
|
"hexConvert": "boolean",
|
||||||
"outputDir": "string",
|
"outputDir": "string",
|
||||||
"parseErrors": "boolean",
|
"parseErrors": "boolean",
|
||||||
"pivotColumn": "string",
|
|
||||||
"saveConfig": "string",
|
"saveConfig": "string",
|
||||||
"scope": "string",
|
"scope": "string",
|
||||||
"testFilter": "string",
|
"testFilter": "string",
|
||||||
@@ -217,23 +218,22 @@ optDict = {
|
|||||||
"dependencies": "boolean",
|
"dependencies": "boolean",
|
||||||
"disableColoring": "boolean",
|
"disableColoring": "boolean",
|
||||||
"googlePage": "integer",
|
"googlePage": "integer",
|
||||||
|
"identifyWaf": "boolean",
|
||||||
"mobile": "boolean",
|
"mobile": "boolean",
|
||||||
"offline": "boolean",
|
"offline": "boolean",
|
||||||
"pageRank": "boolean",
|
"pageRank": "boolean",
|
||||||
"purgeOutput": "boolean",
|
"purgeOutput": "boolean",
|
||||||
|
"skipWaf": "boolean",
|
||||||
"smart": "boolean",
|
"smart": "boolean",
|
||||||
|
"tmpDir": "string",
|
||||||
"wizard": "boolean",
|
"wizard": "boolean",
|
||||||
"verbose": "integer",
|
"verbose": "integer",
|
||||||
},
|
},
|
||||||
"Hidden": {
|
"Hidden": {
|
||||||
"dummy": "boolean",
|
"dummy": "boolean",
|
||||||
"disablePrecon": "boolean",
|
"disablePrecon": "boolean",
|
||||||
"binaryFields": "string",
|
|
||||||
"profile": "boolean",
|
"profile": "boolean",
|
||||||
"cpuThrottle": "integer",
|
|
||||||
"forceDns": "boolean",
|
"forceDns": "boolean",
|
||||||
"identifyWaf": "boolean",
|
|
||||||
"skipWaf": "boolean",
|
|
||||||
"ignore401": "boolean",
|
"ignore401": "boolean",
|
||||||
"smokeTest": "boolean",
|
"smokeTest": "boolean",
|
||||||
"liveTest": "boolean",
|
"liveTest": "boolean",
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ def setDbms(dbms):
|
|||||||
dbms = _.group(1)
|
dbms = _.group(1)
|
||||||
|
|
||||||
Backend.setDbms(dbms)
|
Backend.setDbms(dbms)
|
||||||
|
if kb.resolutionDbms:
|
||||||
|
hashDBWrite(HASHDB_KEYS.DBMS, kb.resolutionDbms)
|
||||||
|
|
||||||
logger.info("the back-end DBMS is %s" % Backend.getDbms())
|
logger.info("the back-end DBMS is %s" % Backend.getDbms())
|
||||||
|
|
||||||
|
|||||||
+27
-14
@@ -10,7 +10,6 @@ import re
|
|||||||
import subprocess
|
import subprocess
|
||||||
import string
|
import string
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import types
|
import types
|
||||||
|
|
||||||
from lib.core.datatype import AttribDict
|
from lib.core.datatype import AttribDict
|
||||||
@@ -20,7 +19,7 @@ from lib.core.enums import OS
|
|||||||
from lib.core.revision import getRevisionNumber
|
from lib.core.revision import getRevisionNumber
|
||||||
|
|
||||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||||
VERSION = "1.0.4.0"
|
VERSION = "1.0.7.0"
|
||||||
REVISION = getRevisionNumber()
|
REVISION = getRevisionNumber()
|
||||||
STABLE = VERSION.count('.') <= 2
|
STABLE = VERSION.count('.') <= 2
|
||||||
VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev")
|
VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev")
|
||||||
@@ -61,6 +60,7 @@ PARTIAL_HEX_VALUE_MARKER = "__PARTIAL_HEX_VALUE__"
|
|||||||
URI_QUESTION_MARKER = "__QUESTION_MARK__"
|
URI_QUESTION_MARKER = "__QUESTION_MARK__"
|
||||||
ASTERISK_MARKER = "__ASTERISK_MARK__"
|
ASTERISK_MARKER = "__ASTERISK_MARK__"
|
||||||
REPLACEMENT_MARKER = "__REPLACEMENT_MARK__"
|
REPLACEMENT_MARKER = "__REPLACEMENT_MARK__"
|
||||||
|
BOUNDED_INJECTION_MARKER = "__BOUNDED_INJECTION_MARK__"
|
||||||
|
|
||||||
RANDOM_INTEGER_MARKER = "[RANDINT]"
|
RANDOM_INTEGER_MARKER = "[RANDINT]"
|
||||||
RANDOM_STRING_MARKER = "[RANDSTR]"
|
RANDOM_STRING_MARKER = "[RANDSTR]"
|
||||||
@@ -69,6 +69,9 @@ PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__"
|
|||||||
CHAR_INFERENCE_MARK = "%c"
|
CHAR_INFERENCE_MARK = "%c"
|
||||||
PRINTABLE_CHAR_REGEX = r"[^\x00-\x1f\x7f-\xff]"
|
PRINTABLE_CHAR_REGEX = r"[^\x00-\x1f\x7f-\xff]"
|
||||||
|
|
||||||
|
# Regular expression used for extraction of table names (useful for (e.g.) MsAccess)
|
||||||
|
SELECT_FROM_TABLE_REGEX = r"\bSELECT .+? FROM (?P<result>[\w.]+)\b"
|
||||||
|
|
||||||
# Regular expression used for recognition of textual content-type
|
# Regular expression used for recognition of textual content-type
|
||||||
TEXT_CONTENT_TYPE_REGEX = r"(?i)(text|form|message|xml|javascript|ecmascript|json)"
|
TEXT_CONTENT_TYPE_REGEX = r"(?i)(text|form|message|xml|javascript|ecmascript|json)"
|
||||||
|
|
||||||
@@ -130,6 +133,9 @@ HTTP_ACCEPT_ENCODING_HEADER_VALUE = "gzip,deflate"
|
|||||||
# Default timeout for running commands over backdoor
|
# Default timeout for running commands over backdoor
|
||||||
BACKDOOR_RUN_CMD_TIMEOUT = 5
|
BACKDOOR_RUN_CMD_TIMEOUT = 5
|
||||||
|
|
||||||
|
# Number of seconds to wait for thread finalization at program end
|
||||||
|
THREAD_FINALIZATION_TIMEOUT = 1
|
||||||
|
|
||||||
# Maximum number of techniques used in inject.py/getValue() per one value
|
# Maximum number of techniques used in inject.py/getValue() per one value
|
||||||
MAX_TECHNIQUES_PER_VALUE = 2
|
MAX_TECHNIQUES_PER_VALUE = 2
|
||||||
|
|
||||||
@@ -281,12 +287,16 @@ BLANK = "<blank>"
|
|||||||
# String representation for current database
|
# String representation for current database
|
||||||
CURRENT_DB = "CD"
|
CURRENT_DB = "CD"
|
||||||
|
|
||||||
|
# Regular expressions used for finding file paths in error messages
|
||||||
|
FILE_PATH_REGEXES = (r" in (file )?<b>(?P<result>.*?)</b> on line", r"(?:[>(\[\s])(?P<result>[A-Za-z]:[\\/][\w.\\/-]*)", r"(?:[>(\[\s])(?P<result>/\w[/\w.-]+)", r"href=['\"]file://(?P<result>/[^'\"]+)")
|
||||||
|
|
||||||
# Regular expressions used for parsing error messages (--parse-errors)
|
# Regular expressions used for parsing error messages (--parse-errors)
|
||||||
ERROR_PARSING_REGEXES = (
|
ERROR_PARSING_REGEXES = (
|
||||||
r"<b>[^<]*(fatal|error|warning|exception)[^<]*</b>:?\s*(?P<result>.+?)<br\s*/?\s*>",
|
r"<b>[^<]*(fatal|error|warning|exception)[^<]*</b>:?\s*(?P<result>.+?)<br\s*/?\s*>",
|
||||||
r"(?m)^(fatal|error|warning|exception):?\s*(?P<result>.+?)$",
|
r"(?m)^(fatal|error|warning|exception):?\s*(?P<result>[^\n]+?)$",
|
||||||
r"<li>Error Type:<br>(?P<result>.+?)</li>",
|
r"<li>Error Type:<br>(?P<result>.+?)</li>",
|
||||||
r"error '[0-9a-f]{8}'((<[^>]+>)|\s)+(?P<result>[^<>]+)",
|
r"error '[0-9a-f]{8}'((<[^>]+>)|\s)+(?P<result>[^<>]+)",
|
||||||
|
r"(?m)^\s*\[[^\n]+(ODBC|JDBC)[^\n]+\](?P<result>[^\]]+in query expression[^\n]+)$"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Regular expression used for parsing charset info from meta html headers
|
# Regular expression used for parsing charset info from meta html headers
|
||||||
@@ -313,9 +323,6 @@ BURP_REQUEST_REGEX = r"={10,}\s+[^=]+={10,}\s(.+?)\s={10,}"
|
|||||||
# Regex used for parsing XML Burp saved history items
|
# Regex used for parsing XML Burp saved history items
|
||||||
BURP_XML_HISTORY_REGEX = r'<port>(\d+)</port>.+?<request base64="true"><!\[CDATA\[([^]]+)'
|
BURP_XML_HISTORY_REGEX = r'<port>(\d+)</port>.+?<request base64="true"><!\[CDATA\[([^]]+)'
|
||||||
|
|
||||||
# Server header in CloudFlare responses
|
|
||||||
CLOUDFLARE_SERVER_HEADER = "cloudflare-nginx"
|
|
||||||
|
|
||||||
# Encoding used for Unicode data
|
# Encoding used for Unicode data
|
||||||
UNICODE_ENCODING = "utf8"
|
UNICODE_ENCODING = "utf8"
|
||||||
|
|
||||||
@@ -448,7 +455,7 @@ DUMMY_SQL_INJECTION_CHARS = ";()'"
|
|||||||
DUMMY_USER_INJECTION = r"(?i)[^\w](AND|OR)\s+[^\s]+[=><]|\bUNION\b.+\bSELECT\b|\bSELECT\b.+\bFROM\b|\b(CONCAT|information_schema|SLEEP|DELAY)\b"
|
DUMMY_USER_INJECTION = r"(?i)[^\w](AND|OR)\s+[^\s]+[=><]|\bUNION\b.+\bSELECT\b|\bSELECT\b.+\bFROM\b|\b(CONCAT|information_schema|SLEEP|DELAY)\b"
|
||||||
|
|
||||||
# Extensions skipped by crawler
|
# Extensions skipped by crawler
|
||||||
CRAWL_EXCLUDE_EXTENSIONS = ("gif", "jpg", "jpeg", "image", "jar", "tif", "bmp", "war", "ear", "mpg", "mpeg", "wmv", "mpeg", "scm", "iso", "dmp", "dll", "cab", "so", "avi", "mkv", "bin", "iso", "tar", "png", "pdf", "ps", "wav", "mp3", "mp4", "au", "aiff", "aac", "zip", "rar", "7z", "gz", "flv", "mov", "doc", "docx", "xls", "dot", "dotx", "xlt", "xlsx", "ppt", "pps", "pptx")
|
CRAWL_EXCLUDE_EXTENSIONS = ('3ds', '3g2', '3gp', '7z', 'DS_Store', 'a', 'aac', 'adp', 'ai', 'aif', 'aiff', 'apk', 'ar', 'asf', 'au', 'avi', 'bak', 'bin', 'bk', 'bmp', 'btif', 'bz2', 'cab', 'caf', 'cgm', 'cmx', 'cpio', 'cr2', 'dat', 'deb', 'djvu', 'dll', 'dmg', 'dmp', 'dng', 'doc', 'docx', 'dot', 'dotx', 'dra', 'dsk', 'dts', 'dtshd', 'dvb', 'dwg', 'dxf', 'ear', 'ecelp4800', 'ecelp7470', 'ecelp9600', 'egg', 'eol', 'eot', 'epub', 'exe', 'f4v', 'fbs', 'fh', 'fla', 'flac', 'fli', 'flv', 'fpx', 'fst', 'fvt', 'g3', 'gif', 'gz', 'h261', 'h263', 'h264', 'ico', 'ief', 'image', 'img', 'ipa', 'iso', 'jar', 'jpeg', 'jpg', 'jpgv', 'jpm', 'jxr', 'ktx', 'lvp', 'lz', 'lzma', 'lzo', 'm3u', 'm4a', 'm4v', 'mar', 'mdi', 'mid', 'mj2', 'mka', 'mkv', 'mmr', 'mng', 'mov', 'movie', 'mp3', 'mp4', 'mp4a', 'mpeg', 'mpg', 'mpga', 'mxu', 'nef', 'npx', 'o', 'oga', 'ogg', 'ogv', 'otf', 'pbm', 'pcx', 'pdf', 'pea', 'pgm', 'pic', 'png', 'pnm', 'ppm', 'pps', 'ppt', 'pptx', 'ps', 'psd', 'pya', 'pyc', 'pyo', 'pyv', 'qt', 'rar', 'ras', 'raw', 'rgb', 'rip', 'rlc', 'rz', 's3m', 's7z', 'scm', 'scpt', 'sgi', 'shar', 'sil', 'smv', 'so', 'sub', 'swf', 'tar', 'tbz2', 'tga', 'tgz', 'tif', 'tiff', 'tlz', 'ts', 'ttf', 'uvh', 'uvi', 'uvm', 'uvp', 'uvs', 'uvu', 'viv', 'vob', 'war', 'wav', 'wax', 'wbmp', 'wdp', 'weba', 'webm', 'webp', 'whl', 'wm', 'wma', 'wmv', 'wmx', 'woff', 'woff2', 'wvx', 'xbm', 'xif', 'xls', 'xlsx', 'xlt', 'xm', 'xpi', 'xpm', 'xwd', 'xz', 'z', 'zip', 'zipx')
|
||||||
|
|
||||||
# Patterns often seen in HTTP headers containing custom injection marking character
|
# Patterns often seen in HTTP headers containing custom injection marking character
|
||||||
PROBLEMATIC_CUSTOM_INJECTION_PATTERNS = r"(;q=[^;']+)|(\*/\*)"
|
PROBLEMATIC_CUSTOM_INJECTION_PATTERNS = r"(;q=[^;']+)|(\*/\*)"
|
||||||
@@ -459,8 +466,8 @@ BRUTE_TABLE_EXISTS_TEMPLATE = "EXISTS(SELECT %d FROM %s)"
|
|||||||
# Template used for common column existence check
|
# Template used for common column existence check
|
||||||
BRUTE_COLUMN_EXISTS_TEMPLATE = "EXISTS(SELECT %s FROM %s)"
|
BRUTE_COLUMN_EXISTS_TEMPLATE = "EXISTS(SELECT %s FROM %s)"
|
||||||
|
|
||||||
# Payload used for checking of existence of IDS/WAF (dummier the better)
|
# Payload used for checking of existence of IDS/IPS/WAF (dummier the better)
|
||||||
IDS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,2,3,table_name FROM information_schema.tables WHERE 2>1-- ../../../etc/passwd"
|
IDS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,NULL,'<script>alert(\"XSS\")</script>',table_name FROM information_schema.tables WHERE 2>1--/**/; EXEC xp_cmdshell('cat ../../../etc/passwd')#"
|
||||||
|
|
||||||
# Data inside shellcodeexec to be filled with random string
|
# Data inside shellcodeexec to be filled with random string
|
||||||
SHELLCODEEXEC_RANDOM_STRING_MARKER = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
SHELLCODEEXEC_RANDOM_STRING_MARKER = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||||
@@ -533,7 +540,7 @@ HASHDB_FLUSH_RETRIES = 3
|
|||||||
HASHDB_END_TRANSACTION_RETRIES = 3
|
HASHDB_END_TRANSACTION_RETRIES = 3
|
||||||
|
|
||||||
# Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism)
|
# Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism)
|
||||||
HASHDB_MILESTONE_VALUE = "JHjrBugdDA" # "".join(random.sample(string.ascii_letters, 10))
|
HASHDB_MILESTONE_VALUE = "pGBhWXgbtJ" # import random, string; print "".join(random.sample(string.ascii_letters, 10))
|
||||||
|
|
||||||
# Warn user of possible delay due to large page dump in full UNION query injections
|
# Warn user of possible delay due to large page dump in full UNION query injections
|
||||||
LARGE_OUTPUT_THRESHOLD = 1024 ** 2
|
LARGE_OUTPUT_THRESHOLD = 1024 ** 2
|
||||||
@@ -562,6 +569,9 @@ HEURISTIC_CHECK_ALPHABET = ('"', '\'', ')', '(', ',', '.')
|
|||||||
# String used for dummy non-SQLi (e.g. XSS) heuristic checks of a tested parameter value
|
# String used for dummy non-SQLi (e.g. XSS) heuristic checks of a tested parameter value
|
||||||
DUMMY_NON_SQLI_CHECK_APPENDIX = "<'\">"
|
DUMMY_NON_SQLI_CHECK_APPENDIX = "<'\">"
|
||||||
|
|
||||||
|
# Regular expression used for recognition of file inclusion errors
|
||||||
|
FI_ERROR_REGEX = "(?i)[^\n]*(no such file|failed (to )?open)[^\n]*"
|
||||||
|
|
||||||
# Length of prefix and suffix used in non-SQLI heuristic checks
|
# Length of prefix and suffix used in non-SQLI heuristic checks
|
||||||
NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6
|
NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6
|
||||||
|
|
||||||
@@ -571,6 +581,9 @@ MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024
|
|||||||
# Maximum response total page size (trimmed if larger)
|
# Maximum response total page size (trimmed if larger)
|
||||||
MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024
|
MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024
|
||||||
|
|
||||||
|
# For preventing MemoryError exceptions (caused when using large sequences in difflib.SequenceMatcher)
|
||||||
|
MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024
|
||||||
|
|
||||||
# Maximum (multi-threaded) length of entry in bisection algorithm
|
# Maximum (multi-threaded) length of entry in bisection algorithm
|
||||||
MAX_BISECTION_LENGTH = 50 * 1024 * 1024
|
MAX_BISECTION_LENGTH = 50 * 1024 * 1024
|
||||||
|
|
||||||
@@ -578,7 +591,7 @@ MAX_BISECTION_LENGTH = 50 * 1024 * 1024
|
|||||||
LARGE_CHUNK_TRIM_MARKER = "__TRIMMED_CONTENT__"
|
LARGE_CHUNK_TRIM_MARKER = "__TRIMMED_CONTENT__"
|
||||||
|
|
||||||
# Generic SQL comment formation
|
# Generic SQL comment formation
|
||||||
GENERIC_SQL_COMMENT = "-- -"
|
GENERIC_SQL_COMMENT = "-- [RANDSTR]"
|
||||||
|
|
||||||
# Threshold value for turning back on time auto-adjustment mechanism
|
# Threshold value for turning back on time auto-adjustment mechanism
|
||||||
VALID_TIME_CHARS_RUN_THRESHOLD = 100
|
VALID_TIME_CHARS_RUN_THRESHOLD = 100
|
||||||
@@ -587,7 +600,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100
|
|||||||
CHECK_ZERO_COLUMNS_THRESHOLD = 10
|
CHECK_ZERO_COLUMNS_THRESHOLD = 10
|
||||||
|
|
||||||
# Boldify all logger messages containing these "patterns"
|
# Boldify all logger messages containing these "patterns"
|
||||||
BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CloudFlare")
|
BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved")
|
||||||
|
|
||||||
# Generic www root directory names
|
# Generic www root directory names
|
||||||
GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "wwwroot", "www")
|
GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "wwwroot", "www")
|
||||||
@@ -599,7 +612,7 @@ MAX_HELP_OPTION_LENGTH = 18
|
|||||||
MAX_CONNECT_RETRIES = 100
|
MAX_CONNECT_RETRIES = 100
|
||||||
|
|
||||||
# Strings for detecting formatting errors
|
# Strings for detecting formatting errors
|
||||||
FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Failed to convert", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal")
|
FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Conversion failed", "String or binary data would be truncated", "Failed to convert", "unable to interpret text value", "Input string was not in a correct format", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal", "DataTypeMismatchException", "CF_SQL_INTEGER", "InvalidParamTypeException", "Invalid parameter type")
|
||||||
|
|
||||||
# Regular expression used for extracting ASP.NET view state values
|
# Regular expression used for extracting ASP.NET view state values
|
||||||
VIEWSTATE_REGEX = r'(?i)(?P<name>__VIEWSTATE[^"]*)[^>]+value="(?P<result>[^"]+)'
|
VIEWSTATE_REGEX = r'(?i)(?P<name>__VIEWSTATE[^"]*)[^>]+value="(?P<result>[^"]+)'
|
||||||
@@ -680,7 +693,7 @@ BRUTE_DOC_ROOT_PREFIXES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Suffixes used in brute force search for web server document root
|
# Suffixes used in brute force search for web server document root
|
||||||
BRUTE_DOC_ROOT_SUFFIXES = ("", "html", "htdocs", "httpdocs", "php", "public", "src", "site", "build", "web", "data", "sites/all", "www/build")
|
BRUTE_DOC_ROOT_SUFFIXES = ("", "html", "htdocs", "httpdocs", "php", "public", "src", "site", "build", "web", "www", "data", "sites/all", "www/build")
|
||||||
|
|
||||||
# String used for marking target name inside used brute force web server document root
|
# String used for marking target name inside used brute force web server document root
|
||||||
BRUTE_DOC_ROOT_TARGET_MARK = "%TARGET%"
|
BRUTE_DOC_ROOT_TARGET_MARK = "%TARGET%"
|
||||||
|
|||||||
+30
-23
@@ -21,6 +21,7 @@ from lib.core.common import intersect
|
|||||||
from lib.core.common import normalizeUnicode
|
from lib.core.common import normalizeUnicode
|
||||||
from lib.core.common import openFile
|
from lib.core.common import openFile
|
||||||
from lib.core.common import paramToDict
|
from lib.core.common import paramToDict
|
||||||
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.common import resetCookieJar
|
from lib.core.common import resetCookieJar
|
||||||
from lib.core.common import urldecode
|
from lib.core.common import urldecode
|
||||||
@@ -35,6 +36,7 @@ from lib.core.dump import dumper
|
|||||||
from lib.core.enums import HASHDB_KEYS
|
from lib.core.enums import HASHDB_KEYS
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.enums import HTTPMETHOD
|
from lib.core.enums import HTTPMETHOD
|
||||||
|
from lib.core.enums import MKSTEMP_PREFIX
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
from lib.core.enums import POST_HINT
|
from lib.core.enums import POST_HINT
|
||||||
from lib.core.exception import SqlmapFilePathException
|
from lib.core.exception import SqlmapFilePathException
|
||||||
@@ -214,9 +216,9 @@ def _setRequestParams():
|
|||||||
|
|
||||||
if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and not CUSTOM_INJECTION_MARK_CHAR in (conf.data or "") and conf.url.startswith("http"):
|
if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and not CUSTOM_INJECTION_MARK_CHAR in (conf.data or "") and conf.url.startswith("http"):
|
||||||
warnMsg = "you've provided target URL without any GET "
|
warnMsg = "you've provided target URL without any GET "
|
||||||
warnMsg += "parameters (e.g. www.site.com/article.php?id=1) "
|
warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') "
|
||||||
warnMsg += "and without providing any POST parameters "
|
warnMsg += "and without providing any POST parameters "
|
||||||
warnMsg += "through --data option"
|
warnMsg += "through option '--data'"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
message = "do you want to try URI injections "
|
message = "do you want to try URI injections "
|
||||||
@@ -370,7 +372,7 @@ def _setRequestParams():
|
|||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
if conf.csrfToken:
|
if conf.csrfToken:
|
||||||
if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders) and not conf.csrfToken in conf.paramDict.get(PLACE.COOKIE, {}):
|
if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % re.escape(conf.csrfToken), conf.data or "") and not conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders) and not conf.csrfToken in conf.paramDict.get(PLACE.COOKIE, {}):
|
||||||
errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken
|
errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken
|
||||||
errMsg += "found in provided GET, POST, Cookie or header values"
|
errMsg += "found in provided GET, POST, Cookie or header values"
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
@@ -531,7 +533,7 @@ def _setResultsFile():
|
|||||||
except (OSError, IOError), ex:
|
except (OSError, IOError), ex:
|
||||||
try:
|
try:
|
||||||
warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFilename, getUnicode(ex))
|
warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFilename, getUnicode(ex))
|
||||||
conf.resultsFilename = tempfile.mkstemp(prefix="sqlmapresults-", suffix=".csv")[1]
|
conf.resultsFilename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv")[1]
|
||||||
conf.resultsFP = openFile(conf.resultsFilename, "w+", UNICODE_ENCODING, buffering=0)
|
conf.resultsFP = openFile(conf.resultsFilename, "w+", UNICODE_ENCODING, buffering=0)
|
||||||
warnMsg += "Using temporary file '%s' instead" % conf.resultsFilename
|
warnMsg += "Using temporary file '%s' instead" % conf.resultsFilename
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
@@ -542,7 +544,7 @@ def _setResultsFile():
|
|||||||
errMsg += "create temporary files and/or directories"
|
errMsg += "create temporary files and/or directories"
|
||||||
raise SqlmapSystemException(errMsg)
|
raise SqlmapSystemException(errMsg)
|
||||||
|
|
||||||
conf.resultsFP.writelines("Target URL,Place,Parameter,Techniques%s" % os.linesep)
|
conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep)
|
||||||
|
|
||||||
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFilename)
|
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFilename)
|
||||||
|
|
||||||
@@ -603,28 +605,33 @@ def _createTargetDirs():
|
|||||||
Create the output directory.
|
Create the output directory.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
|
try:
|
||||||
try:
|
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
|
||||||
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
|
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
|
||||||
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
|
|
||||||
|
_ = os.path.join(paths.SQLMAP_OUTPUT_PATH, randomStr())
|
||||||
|
open(_, "w+b").close()
|
||||||
|
os.remove(_)
|
||||||
|
|
||||||
|
if conf.outputDir:
|
||||||
warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH
|
warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
except (OSError, IOError), ex:
|
except (OSError, IOError), ex:
|
||||||
try:
|
try:
|
||||||
tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
|
tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
|
||||||
except Exception, _:
|
except Exception, _:
|
||||||
errMsg = "unable to write to the temporary directory ('%s'). " % _
|
errMsg = "unable to write to the temporary directory ('%s'). " % _
|
||||||
errMsg += "Please make sure that your disk is not full and "
|
errMsg += "Please make sure that your disk is not full and "
|
||||||
errMsg += "that you have sufficient write permissions to "
|
errMsg += "that you have sufficient write permissions to "
|
||||||
errMsg += "create temporary files and/or directories"
|
errMsg += "create temporary files and/or directories"
|
||||||
raise SqlmapSystemException(errMsg)
|
raise SqlmapSystemException(errMsg)
|
||||||
|
|
||||||
warnMsg = "unable to create regular output directory "
|
warnMsg = "unable to %s output directory " % ("create" if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH) else "write to the")
|
||||||
warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
|
warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
|
||||||
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
|
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
paths.SQLMAP_OUTPUT_PATH = tempDir
|
paths.SQLMAP_OUTPUT_PATH = tempDir
|
||||||
|
|
||||||
conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname)))
|
conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname)))
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -25,6 +25,7 @@ from lib.core.common import readXmlFile
|
|||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import paths
|
from lib.core.data import paths
|
||||||
|
from lib.core.enums import MKSTEMP_PREFIX
|
||||||
from lib.core.exception import SqlmapBaseException
|
from lib.core.exception import SqlmapBaseException
|
||||||
from lib.core.exception import SqlmapNotVulnerableException
|
from lib.core.exception import SqlmapNotVulnerableException
|
||||||
from lib.core.log import LOGGER_HANDLER
|
from lib.core.log import LOGGER_HANDLER
|
||||||
@@ -235,7 +236,7 @@ def initCase(switches, count):
|
|||||||
Failures.failedParseOn = None
|
Failures.failedParseOn = None
|
||||||
Failures.failedTraceBack = None
|
Failures.failedTraceBack = None
|
||||||
|
|
||||||
paths.SQLMAP_OUTPUT_PATH = tempfile.mkdtemp(prefix="sqlmaptest-%d-" % count)
|
paths.SQLMAP_OUTPUT_PATH = tempfile.mkdtemp(prefix="%s%d-" % (MKSTEMP_PREFIX.TESTING, count))
|
||||||
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
||||||
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
|
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import difflib
|
import difflib
|
||||||
|
import random
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
@@ -43,6 +44,7 @@ class _ThreadData(threading.local):
|
|||||||
self.inTransaction = False
|
self.inTransaction = False
|
||||||
self.lastComparisonPage = None
|
self.lastComparisonPage = None
|
||||||
self.lastComparisonHeaders = None
|
self.lastComparisonHeaders = None
|
||||||
|
self.lastComparisonCode = None
|
||||||
self.lastErrorPage = None
|
self.lastErrorPage = None
|
||||||
self.lastHTTPError = None
|
self.lastHTTPError = None
|
||||||
self.lastRedirectMsg = None
|
self.lastRedirectMsg = None
|
||||||
@@ -51,6 +53,7 @@ class _ThreadData(threading.local):
|
|||||||
self.lastRequestMsg = None
|
self.lastRequestMsg = None
|
||||||
self.lastRequestUID = 0
|
self.lastRequestUID = 0
|
||||||
self.lastRedirectURL = None
|
self.lastRedirectURL = None
|
||||||
|
self.random = random.WichmannHill()
|
||||||
self.resumed = False
|
self.resumed = False
|
||||||
self.retriesCount = 0
|
self.retriesCount = 0
|
||||||
self.seqMatcher = difflib.SequenceMatcher(None)
|
self.seqMatcher = difflib.SequenceMatcher(None)
|
||||||
@@ -199,7 +202,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
|
|||||||
kb.threadException = False
|
kb.threadException = False
|
||||||
|
|
||||||
for lock in kb.locks.values():
|
for lock in kb.locks.values():
|
||||||
if lock.locked_lock():
|
if lock.locked():
|
||||||
try:
|
try:
|
||||||
lock.release()
|
lock.release()
|
||||||
except thread.error:
|
except thread.error:
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import zipfile
|
|||||||
from lib.core.common import getSafeExString
|
from lib.core.common import getSafeExString
|
||||||
from lib.core.exception import SqlmapDataException
|
from lib.core.exception import SqlmapDataException
|
||||||
from lib.core.exception import SqlmapInstallationException
|
from lib.core.exception import SqlmapInstallationException
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
|
||||||
|
|
||||||
class Wordlist(object):
|
class Wordlist(object):
|
||||||
"""
|
"""
|
||||||
@@ -45,7 +44,7 @@ class Wordlist(object):
|
|||||||
try:
|
try:
|
||||||
_ = zipfile.ZipFile(self.current, 'r')
|
_ = zipfile.ZipFile(self.current, 'r')
|
||||||
except zipfile.error, ex:
|
except zipfile.error, ex:
|
||||||
errMsg = "something seems to be wrong with "
|
errMsg = "something appears to be wrong with "
|
||||||
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
|
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
|
||||||
errMsg += "sure that you haven't made any changes to it"
|
errMsg += "sure that you haven't made any changes to it"
|
||||||
raise SqlmapInstallationException, errMsg
|
raise SqlmapInstallationException, errMsg
|
||||||
@@ -71,7 +70,7 @@ class Wordlist(object):
|
|||||||
try:
|
try:
|
||||||
retVal = self.iter.next().rstrip()
|
retVal = self.iter.next().rstrip()
|
||||||
except zipfile.error, ex:
|
except zipfile.error, ex:
|
||||||
errMsg = "something seems to be wrong with "
|
errMsg = "something appears to be wrong with "
|
||||||
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
|
errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex))
|
||||||
errMsg += "sure that you haven't made any changes to it"
|
errMsg += "sure that you haven't made any changes to it"
|
||||||
raise SqlmapInstallationException, errMsg
|
raise SqlmapInstallationException, errMsg
|
||||||
|
|||||||
+28
-25
@@ -17,6 +17,7 @@ from optparse import SUPPRESS_HELP
|
|||||||
|
|
||||||
from lib.core.common import checkDeprecatedOptions
|
from lib.core.common import checkDeprecatedOptions
|
||||||
from lib.core.common import checkSystemEncoding
|
from lib.core.common import checkSystemEncoding
|
||||||
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.common import expandMnemonics
|
from lib.core.common import expandMnemonics
|
||||||
from lib.core.common import getUnicode
|
from lib.core.common import getUnicode
|
||||||
from lib.core.data import cmdLineOptions
|
from lib.core.data import cmdLineOptions
|
||||||
@@ -30,6 +31,7 @@ from lib.core.settings import BASIC_HELP_ITEMS
|
|||||||
from lib.core.settings import DUMMY_URL
|
from lib.core.settings import DUMMY_URL
|
||||||
from lib.core.settings import IS_WIN
|
from lib.core.settings import IS_WIN
|
||||||
from lib.core.settings import MAX_HELP_OPTION_LENGTH
|
from lib.core.settings import MAX_HELP_OPTION_LENGTH
|
||||||
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
from lib.core.settings import VERSION_STRING
|
from lib.core.settings import VERSION_STRING
|
||||||
from lib.core.shell import autoCompletion
|
from lib.core.shell import autoCompletion
|
||||||
from lib.core.shell import clearHistory
|
from lib.core.shell import clearHistory
|
||||||
@@ -46,7 +48,7 @@ def cmdLineParser(argv=None):
|
|||||||
|
|
||||||
checkSystemEncoding()
|
checkSystemEncoding()
|
||||||
|
|
||||||
_ = getUnicode(os.path.basename(argv[0]), encoding=sys.getfilesystemencoding())
|
_ = getUnicode(os.path.basename(argv[0]), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
|
||||||
|
|
||||||
usage = "%s%s [options]" % ("python " if not IS_WIN else "", \
|
usage = "%s%s [options]" % ("python " if not IS_WIN else "", \
|
||||||
"\"%s\"" % _ if " " in _ else _)
|
"\"%s\"" % _ if " " in _ else _)
|
||||||
@@ -464,6 +466,9 @@ def cmdLineParser(argv=None):
|
|||||||
help="Exclude DBMS system databases when "
|
help="Exclude DBMS system databases when "
|
||||||
"enumerating tables")
|
"enumerating tables")
|
||||||
|
|
||||||
|
enumeration.add_option("--pivot-column", dest="pivotColumn",
|
||||||
|
help="Pivot column name")
|
||||||
|
|
||||||
enumeration.add_option("--where", dest="dumpWhere",
|
enumeration.add_option("--where", dest="dumpWhere",
|
||||||
help="Use WHERE condition while table dumping")
|
help="Use WHERE condition while table dumping")
|
||||||
|
|
||||||
@@ -617,6 +622,9 @@ def cmdLineParser(argv=None):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Never ask for user input, use the default behaviour")
|
help="Never ask for user input, use the default behaviour")
|
||||||
|
|
||||||
|
general.add_option("--binary-fields", dest="binaryFields",
|
||||||
|
help="Result fields having binary values (e.g. \"digest\")")
|
||||||
|
|
||||||
general.add_option("--charset", dest="charset",
|
general.add_option("--charset", dest="charset",
|
||||||
help="Force character encoding used for data retrieval")
|
help="Force character encoding used for data retrieval")
|
||||||
|
|
||||||
@@ -662,9 +670,6 @@ def cmdLineParser(argv=None):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Parse and display DBMS error messages from responses")
|
help="Parse and display DBMS error messages from responses")
|
||||||
|
|
||||||
general.add_option("--pivot-column", dest="pivotColumn",
|
|
||||||
help="Pivot column name")
|
|
||||||
|
|
||||||
general.add_option("--save", dest="saveConfig",
|
general.add_option("--save", dest="saveConfig",
|
||||||
help="Save options to a configuration INI file")
|
help="Save options to a configuration INI file")
|
||||||
|
|
||||||
@@ -716,10 +721,6 @@ def cmdLineParser(argv=None):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Make a thorough testing for a WAF/IPS/IDS protection")
|
help="Make a thorough testing for a WAF/IPS/IDS protection")
|
||||||
|
|
||||||
miscellaneous.add_option("--skip-waf", dest="skipWaf",
|
|
||||||
action="store_true",
|
|
||||||
help="Skip heuristic detection of WAF/IPS/IDS protection")
|
|
||||||
|
|
||||||
miscellaneous.add_option("--mobile", dest="mobile",
|
miscellaneous.add_option("--mobile", dest="mobile",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Imitate smartphone through HTTP User-Agent header")
|
help="Imitate smartphone through HTTP User-Agent header")
|
||||||
@@ -736,12 +737,19 @@ def cmdLineParser(argv=None):
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Safely remove all content from output directory")
|
help="Safely remove all content from output directory")
|
||||||
|
|
||||||
|
miscellaneous.add_option("--skip-waf", dest="skipWaf",
|
||||||
|
action="store_true",
|
||||||
|
help="Skip heuristic detection of WAF/IPS/IDS protection")
|
||||||
|
|
||||||
miscellaneous.add_option("--smart", dest="smart",
|
miscellaneous.add_option("--smart", dest="smart",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Conduct thorough tests only if positive heuristic(s)")
|
help="Conduct thorough tests only if positive heuristic(s)")
|
||||||
|
|
||||||
miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",
|
miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",
|
||||||
help="Prompt for an interactive sqlmap shell")
|
help="Prompt for an interactive sqlmap shell")
|
||||||
|
|
||||||
|
miscellaneous.add_option("--tmp-dir", dest="tmpDir",
|
||||||
|
help="Local directory for storing temporary files")
|
||||||
|
|
||||||
miscellaneous.add_option("--wizard", dest="wizard",
|
miscellaneous.add_option("--wizard", dest="wizard",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@@ -760,12 +768,6 @@ def cmdLineParser(argv=None):
|
|||||||
parser.add_option("--profile", dest="profile", action="store_true",
|
parser.add_option("--profile", dest="profile", action="store_true",
|
||||||
help=SUPPRESS_HELP)
|
help=SUPPRESS_HELP)
|
||||||
|
|
||||||
parser.add_option("--binary-fields", dest="binaryFields",
|
|
||||||
help=SUPPRESS_HELP)
|
|
||||||
|
|
||||||
parser.add_option("--cpu-throttle", dest="cpuThrottle", type="int",
|
|
||||||
help=SUPPRESS_HELP)
|
|
||||||
|
|
||||||
parser.add_option("--force-dns", dest="forceDns", action="store_true",
|
parser.add_option("--force-dns", dest="forceDns", action="store_true",
|
||||||
help=SUPPRESS_HELP)
|
help=SUPPRESS_HELP)
|
||||||
|
|
||||||
@@ -809,12 +811,12 @@ def cmdLineParser(argv=None):
|
|||||||
parser.formatter._format_option_strings = parser.formatter.format_option_strings
|
parser.formatter._format_option_strings = parser.formatter.format_option_strings
|
||||||
parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser, type(parser))
|
parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser, type(parser))
|
||||||
|
|
||||||
# Dirty hack for making a short option -hh
|
# Dirty hack for making a short option '-hh'
|
||||||
option = parser.get_option("--hh")
|
option = parser.get_option("--hh")
|
||||||
option._short_opts = ["-hh"]
|
option._short_opts = ["-hh"]
|
||||||
option._long_opts = []
|
option._long_opts = []
|
||||||
|
|
||||||
# Dirty hack for inherent help message of switch -h
|
# Dirty hack for inherent help message of switch '-h'
|
||||||
option = parser.get_option("-h")
|
option = parser.get_option("-h")
|
||||||
option.help = option.help.capitalize().replace("this help", "basic help")
|
option.help = option.help.capitalize().replace("this help", "basic help")
|
||||||
|
|
||||||
@@ -824,7 +826,7 @@ def cmdLineParser(argv=None):
|
|||||||
extraHeaders = []
|
extraHeaders = []
|
||||||
|
|
||||||
for arg in argv:
|
for arg in argv:
|
||||||
_.append(getUnicode(arg, encoding=sys.getfilesystemencoding()))
|
_.append(getUnicode(arg, encoding=sys.getfilesystemencoding() or UNICODE_ENCODING))
|
||||||
|
|
||||||
argv = _
|
argv = _
|
||||||
checkDeprecatedOptions(argv)
|
checkDeprecatedOptions(argv)
|
||||||
@@ -862,13 +864,13 @@ def cmdLineParser(argv=None):
|
|||||||
continue
|
continue
|
||||||
elif command.lower() == "clear":
|
elif command.lower() == "clear":
|
||||||
clearHistory()
|
clearHistory()
|
||||||
print "[i] history cleared"
|
dataToStdout("[i] history cleared\n")
|
||||||
saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)
|
saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)
|
||||||
elif command.lower() in ("x", "q", "exit", "quit"):
|
elif command.lower() in ("x", "q", "exit", "quit"):
|
||||||
raise SqlmapShellQuitException
|
raise SqlmapShellQuitException
|
||||||
elif command[0] != '-':
|
elif command[0] != '-':
|
||||||
print "[!] invalid option(s) provided"
|
dataToStdout("[!] invalid option(s) provided\n")
|
||||||
print "[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'"
|
dataToStdout("[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'\n")
|
||||||
else:
|
else:
|
||||||
saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)
|
saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)
|
||||||
loadHistory(AUTOCOMPLETE_TYPE.SQLMAP)
|
loadHistory(AUTOCOMPLETE_TYPE.SQLMAP)
|
||||||
@@ -885,7 +887,8 @@ def cmdLineParser(argv=None):
|
|||||||
if argv[i] == "-hh":
|
if argv[i] == "-hh":
|
||||||
argv[i] = "-h"
|
argv[i] = "-h"
|
||||||
elif re.search(r"\A-\w=.+", argv[i]):
|
elif re.search(r"\A-\w=.+", argv[i]):
|
||||||
print "[!] potentially miswritten (illegal '=') short option detected ('%s')" % argv[i]
|
dataToStdout("[!] potentially miswritten (illegal '=') short option detected ('%s')\n" % argv[i])
|
||||||
|
raise SystemExit
|
||||||
elif argv[i] == "-H":
|
elif argv[i] == "-H":
|
||||||
if i + 1 < len(argv):
|
if i + 1 < len(argv):
|
||||||
extraHeaders.append(argv[i + 1])
|
extraHeaders.append(argv[i + 1])
|
||||||
@@ -910,11 +913,11 @@ def cmdLineParser(argv=None):
|
|||||||
try:
|
try:
|
||||||
(args, _) = parser.parse_args(argv)
|
(args, _) = parser.parse_args(argv)
|
||||||
except UnicodeEncodeError, ex:
|
except UnicodeEncodeError, ex:
|
||||||
print "\n[!] %s" % ex.object.encode("unicode-escape")
|
dataToStdout("\n[!] %s\n" % ex.object.encode("unicode-escape"))
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
if "-h" in argv and not advancedHelp:
|
if "-h" in argv and not advancedHelp:
|
||||||
print "\n[!] to see full list of options run with '-hh'"
|
dataToStdout("\n[!] to see full list of options run with '-hh'\n")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if extraHeaders:
|
if extraHeaders:
|
||||||
@@ -946,7 +949,7 @@ def cmdLineParser(argv=None):
|
|||||||
except SystemExit:
|
except SystemExit:
|
||||||
# Protection against Windows dummy double clicking
|
# Protection against Windows dummy double clicking
|
||||||
if IS_WIN:
|
if IS_WIN:
|
||||||
print "\nPress Enter to continue...",
|
dataToStdout("\nPress Enter to continue...")
|
||||||
raw_input()
|
raw_input()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|||||||
+12
-2
@@ -24,7 +24,8 @@ class HTMLHandler(ContentHandler):
|
|||||||
ContentHandler.__init__(self)
|
ContentHandler.__init__(self)
|
||||||
|
|
||||||
self._dbms = None
|
self._dbms = None
|
||||||
self._page = page
|
self._page = (page or "")
|
||||||
|
self._lower_page = self._page.lower()
|
||||||
|
|
||||||
self.dbms = None
|
self.dbms = None
|
||||||
|
|
||||||
@@ -33,11 +34,20 @@ class HTMLHandler(ContentHandler):
|
|||||||
threadData.lastErrorPage = (threadData.lastRequestUID, self._page)
|
threadData.lastErrorPage = (threadData.lastRequestUID, self._page)
|
||||||
|
|
||||||
def startElement(self, name, attrs):
|
def startElement(self, name, attrs):
|
||||||
|
if self.dbms:
|
||||||
|
return
|
||||||
|
|
||||||
if name == "dbms":
|
if name == "dbms":
|
||||||
self._dbms = attrs.get("value")
|
self._dbms = attrs.get("value")
|
||||||
|
|
||||||
elif name == "error":
|
elif name == "error":
|
||||||
if re.search(attrs.get("regexp"), self._page, re.I):
|
regexp = attrs.get("regexp")
|
||||||
|
if regexp not in kb.cache.regex:
|
||||||
|
keywords = re.findall("\w+", re.sub(r"\\.", " ", regexp))
|
||||||
|
keywords = sorted(keywords, key=len)
|
||||||
|
kb.cache.regex[regexp] = keywords[-1].lower()
|
||||||
|
|
||||||
|
if kb.cache.regex[regexp] in self._lower_page and re.search(regexp, self._page, re.I):
|
||||||
self.dbms = self._dbms
|
self.dbms = self._dbms
|
||||||
self._markAsErrorPage()
|
self._markAsErrorPage()
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ def loadBoundaries():
|
|||||||
try:
|
try:
|
||||||
doc = et.parse(paths.BOUNDARIES_XML)
|
doc = et.parse(paths.BOUNDARIES_XML)
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
errMsg = "something seems to be wrong with "
|
errMsg = "something appears to be wrong with "
|
||||||
errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex))
|
errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex))
|
||||||
errMsg += "sure that you haven't made any changes to it"
|
errMsg += "sure that you haven't made any changes to it"
|
||||||
raise SqlmapInstallationException, errMsg
|
raise SqlmapInstallationException, errMsg
|
||||||
@@ -92,7 +92,7 @@ def loadPayloads():
|
|||||||
try:
|
try:
|
||||||
doc = et.parse(payloadFilePath)
|
doc = et.parse(payloadFilePath)
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
errMsg = "something seems to be wrong with "
|
errMsg = "something appears to be wrong with "
|
||||||
errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex))
|
errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex))
|
||||||
errMsg += "sure that you haven't made any changes to it"
|
errMsg += "sure that you haven't made any changes to it"
|
||||||
raise SqlmapInstallationException, errMsg
|
raise SqlmapInstallationException, errMsg
|
||||||
|
|||||||
+29
-14
@@ -13,6 +13,7 @@ import StringIO
|
|||||||
import struct
|
import struct
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
|
from lib.core.common import Backend
|
||||||
from lib.core.common import extractErrorMessage
|
from lib.core.common import extractErrorMessage
|
||||||
from lib.core.common import extractRegexResult
|
from lib.core.common import extractRegexResult
|
||||||
from lib.core.common import getPublicTypeMembers
|
from lib.core.common import getPublicTypeMembers
|
||||||
@@ -25,6 +26,7 @@ from lib.core.common import singleTimeWarnMessage
|
|||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
|
from lib.core.enums import DBMS
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
from lib.core.exception import SqlmapCompressionException
|
from lib.core.exception import SqlmapCompressionException
|
||||||
@@ -34,6 +36,7 @@ from lib.core.settings import EVENTVALIDATION_REGEX
|
|||||||
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
|
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
|
||||||
from lib.core.settings import META_CHARSET_REGEX
|
from lib.core.settings import META_CHARSET_REGEX
|
||||||
from lib.core.settings import PARSE_HEADERS_LIMIT
|
from lib.core.settings import PARSE_HEADERS_LIMIT
|
||||||
|
from lib.core.settings import SELECT_FROM_TABLE_REGEX
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
from lib.core.settings import VIEWSTATE_REGEX
|
from lib.core.settings import VIEWSTATE_REGEX
|
||||||
from lib.parse.headers import headersParser
|
from lib.parse.headers import headersParser
|
||||||
@@ -91,7 +94,7 @@ def forgeHeaders(items=None):
|
|||||||
if cookie.domain_specified and not conf.hostname.endswith(cookie.domain):
|
if cookie.domain_specified and not conf.hostname.endswith(cookie.domain):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ("%s=" % cookie.name) in headers[HTTP_HEADER.COOKIE]:
|
if ("%s=" % getUnicode(cookie.name)) in headers[HTTP_HEADER.COOKIE]:
|
||||||
if conf.loadCookies:
|
if conf.loadCookies:
|
||||||
conf.httpHeaders = filter(None, ((item if item[0] != HTTP_HEADER.COOKIE else None) for item in conf.httpHeaders))
|
conf.httpHeaders = filter(None, ((item if item[0] != HTTP_HEADER.COOKIE else None) for item in conf.httpHeaders))
|
||||||
elif kb.mergeCookies is None:
|
elif kb.mergeCookies is None:
|
||||||
@@ -103,7 +106,7 @@ def forgeHeaders(items=None):
|
|||||||
kb.mergeCookies = not _ or _[0] in ("y", "Y")
|
kb.mergeCookies = not _ or _[0] in ("y", "Y")
|
||||||
|
|
||||||
if kb.mergeCookies and kb.injection.place != PLACE.COOKIE:
|
if kb.mergeCookies and kb.injection.place != PLACE.COOKIE:
|
||||||
_ = lambda x: re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(cookie.name), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (cookie.name, getUnicode(cookie.value))).replace('\\', r'\\'), x)
|
_ = lambda x: re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), x)
|
||||||
headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE])
|
headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE])
|
||||||
|
|
||||||
if PLACE.COOKIE in conf.parameters:
|
if PLACE.COOKIE in conf.parameters:
|
||||||
@@ -112,7 +115,7 @@ def forgeHeaders(items=None):
|
|||||||
conf.httpHeaders = [(item[0], item[1] if item[0] != HTTP_HEADER.COOKIE else _(item[1])) for item in conf.httpHeaders]
|
conf.httpHeaders = [(item[0], item[1] if item[0] != HTTP_HEADER.COOKIE else _(item[1])) for item in conf.httpHeaders]
|
||||||
|
|
||||||
elif not kb.testMode:
|
elif not kb.testMode:
|
||||||
headers[HTTP_HEADER.COOKIE] += "%s %s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, cookie.name, getUnicode(cookie.value))
|
headers[HTTP_HEADER.COOKIE] += "%s %s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, getUnicode(cookie.name), getUnicode(cookie.value))
|
||||||
|
|
||||||
if kb.testMode and not any((conf.csrfToken, conf.safeUrl)):
|
if kb.testMode and not any((conf.csrfToken, conf.safeUrl)):
|
||||||
resetCookieJar(conf.cj)
|
resetCookieJar(conf.cj)
|
||||||
@@ -150,7 +153,7 @@ def checkCharEncoding(encoding, warn=True):
|
|||||||
return encoding
|
return encoding
|
||||||
|
|
||||||
# Reference: http://www.destructor.de/charsets/index.htm
|
# Reference: http://www.destructor.de/charsets/index.htm
|
||||||
translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932"}
|
translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"}
|
||||||
|
|
||||||
for delimiter in (';', ',', '('):
|
for delimiter in (';', ',', '('):
|
||||||
if delimiter in encoding:
|
if delimiter in encoding:
|
||||||
@@ -258,15 +261,16 @@ def decodePage(page, contentEncoding, contentType):
|
|||||||
|
|
||||||
page = data.read()
|
page = data.read()
|
||||||
except Exception, msg:
|
except Exception, msg:
|
||||||
errMsg = "detected invalid data for declared content "
|
if "<html" not in page: # in some cases, invalid "Content-Encoding" appears for plain HTML (should be ignored)
|
||||||
errMsg += "encoding '%s' ('%s')" % (contentEncoding, msg)
|
errMsg = "detected invalid data for declared content "
|
||||||
singleTimeLogMessage(errMsg, logging.ERROR)
|
errMsg += "encoding '%s' ('%s')" % (contentEncoding, msg)
|
||||||
|
singleTimeLogMessage(errMsg, logging.ERROR)
|
||||||
|
|
||||||
warnMsg = "turning off page compression"
|
warnMsg = "turning off page compression"
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
|
||||||
kb.pageCompress = False
|
kb.pageCompress = False
|
||||||
raise SqlmapCompressionException
|
raise SqlmapCompressionException
|
||||||
|
|
||||||
if not conf.charset:
|
if not conf.charset:
|
||||||
httpCharset, metaCharset = None, None
|
httpCharset, metaCharset = None, None
|
||||||
@@ -330,11 +334,14 @@ def processResponse(page, responseHeaders):
|
|||||||
|
|
||||||
parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None)
|
parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None)
|
||||||
|
|
||||||
|
if not kb.tableFrom and Backend.getIdentifiedDbms() in (DBMS.ACCESS,):
|
||||||
|
kb.tableFrom = extractRegexResult(SELECT_FROM_TABLE_REGEX, page)
|
||||||
|
|
||||||
if conf.parseErrors:
|
if conf.parseErrors:
|
||||||
msg = extractErrorMessage(page)
|
msg = extractErrorMessage(page)
|
||||||
|
|
||||||
if msg:
|
if msg:
|
||||||
logger.warning("parsed DBMS error message: '%s'" % msg)
|
logger.warning("parsed DBMS error message: '%s'" % msg.rstrip('.'))
|
||||||
|
|
||||||
if kb.originalPage is None:
|
if kb.originalPage is None:
|
||||||
for regex in (EVENTVALIDATION_REGEX, VIEWSTATE_REGEX):
|
for regex in (EVENTVALIDATION_REGEX, VIEWSTATE_REGEX):
|
||||||
@@ -347,6 +354,14 @@ def processResponse(page, responseHeaders):
|
|||||||
conf.paramDict[PLACE.POST][name] = value
|
conf.paramDict[PLACE.POST][name] = value
|
||||||
conf.parameters[PLACE.POST] = re.sub("(?i)(%s=)[^&]+" % name, r"\g<1>%s" % value, conf.parameters[PLACE.POST])
|
conf.parameters[PLACE.POST] = re.sub("(?i)(%s=)[^&]+" % name, r"\g<1>%s" % value, conf.parameters[PLACE.POST])
|
||||||
|
|
||||||
|
if not kb.captchaDetected and re.search(r"(?i)captcha", page or ""):
|
||||||
|
for match in re.finditer(r"(?si)<form.+?</form>", page):
|
||||||
|
if re.search(r"(?i)captcha", match.group(0)):
|
||||||
|
kb.captchaDetected = True
|
||||||
|
warnMsg = "potential CAPTCHA protection mechanism detected"
|
||||||
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
break
|
||||||
|
|
||||||
if re.search(BLOCKED_IP_REGEX, page):
|
if re.search(BLOCKED_IP_REGEX, page):
|
||||||
errMsg = "it appears that you have been blocked by the target server"
|
warnMsg = "it appears that you have been blocked by the target server"
|
||||||
singleTimeLogMessage(errMsg, logging.ERROR)
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
|||||||
+22
-44
@@ -21,6 +21,7 @@ from lib.core.settings import DEFAULT_PAGE_ENCODING
|
|||||||
from lib.core.settings import DIFF_TOLERANCE
|
from lib.core.settings import DIFF_TOLERANCE
|
||||||
from lib.core.settings import HTML_TITLE_REGEX
|
from lib.core.settings import HTML_TITLE_REGEX
|
||||||
from lib.core.settings import MIN_RATIO
|
from lib.core.settings import MIN_RATIO
|
||||||
|
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
|
||||||
from lib.core.settings import MAX_RATIO
|
from lib.core.settings import MAX_RATIO
|
||||||
from lib.core.settings import REFLECTED_VALUE_MARKER
|
from lib.core.settings import REFLECTED_VALUE_MARKER
|
||||||
from lib.core.settings import LOWER_RATIO_BOUND
|
from lib.core.settings import LOWER_RATIO_BOUND
|
||||||
@@ -49,12 +50,11 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
|
|||||||
if kb.testMode:
|
if kb.testMode:
|
||||||
threadData.lastComparisonHeaders = listToStrValue(headers.headers) if headers else ""
|
threadData.lastComparisonHeaders = listToStrValue(headers.headers) if headers else ""
|
||||||
threadData.lastComparisonPage = page
|
threadData.lastComparisonPage = page
|
||||||
|
threadData.lastComparisonCode = code
|
||||||
|
|
||||||
if page is None and pageLength is None:
|
if page is None and pageLength is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
seqMatcher = threadData.seqMatcher
|
seqMatcher = threadData.seqMatcher
|
||||||
seqMatcher.set_seq1(kb.pageTemplate)
|
seqMatcher.set_seq1(kb.pageTemplate)
|
||||||
|
|
||||||
@@ -109,59 +109,37 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
|
|||||||
elif isinstance(seqMatcher.a, unicode) and isinstance(page, str):
|
elif isinstance(seqMatcher.a, unicode) and isinstance(page, str):
|
||||||
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
|
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
|
||||||
|
|
||||||
seq1, seq2 = None, None
|
if seqMatcher.a and page and seqMatcher.a == page:
|
||||||
|
ratio = 1
|
||||||
if conf.titles:
|
elif kb.skipSeqMatcher or seqMatcher.a and page and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (seqMatcher.a, page)):
|
||||||
seq1 = extractRegexResult(HTML_TITLE_REGEX, seqMatcher.a)
|
ratio = 1.0 * len(seqMatcher.a) / len(page)
|
||||||
seq2 = extractRegexResult(HTML_TITLE_REGEX, page)
|
if ratio > 1:
|
||||||
|
ratio = 1. / ratio
|
||||||
else:
|
else:
|
||||||
seq1 = getFilteredPageContent(seqMatcher.a, True) if conf.textOnly else seqMatcher.a
|
seq1, seq2 = None, None
|
||||||
seq2 = getFilteredPageContent(page, True) if conf.textOnly else page
|
|
||||||
|
|
||||||
if seq1 is None or seq2 is None:
|
if conf.titles:
|
||||||
return None
|
seq1 = extractRegexResult(HTML_TITLE_REGEX, seqMatcher.a)
|
||||||
|
seq2 = extractRegexResult(HTML_TITLE_REGEX, page)
|
||||||
seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "")
|
|
||||||
seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "")
|
|
||||||
|
|
||||||
while count < min(len(seq1), len(seq2)):
|
|
||||||
if seq1[count] == seq2[count]:
|
|
||||||
count += 1
|
|
||||||
else:
|
else:
|
||||||
break
|
seq1 = getFilteredPageContent(seqMatcher.a, True) if conf.textOnly else seqMatcher.a
|
||||||
|
seq2 = getFilteredPageContent(page, True) if conf.textOnly else page
|
||||||
|
|
||||||
if count:
|
if seq1 is None or seq2 is None:
|
||||||
try:
|
return None
|
||||||
_seq1 = seq1[count:]
|
|
||||||
_seq2 = seq2[count:]
|
|
||||||
except MemoryError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
seq1 = _seq1
|
|
||||||
seq2 = _seq2
|
|
||||||
|
|
||||||
while True:
|
seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "")
|
||||||
try:
|
seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "")
|
||||||
seqMatcher.set_seq1(seq1)
|
|
||||||
except MemoryError:
|
|
||||||
seq1 = seq1[:len(seq1) / 1024]
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
while True:
|
seqMatcher.set_seq1(seq1)
|
||||||
try:
|
seqMatcher.set_seq2(seq2)
|
||||||
seqMatcher.set_seq2(seq2)
|
|
||||||
except MemoryError:
|
|
||||||
seq2 = seq2[:len(seq2) / 1024]
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
ratio = round(seqMatcher.quick_ratio(), 3)
|
ratio = round(seqMatcher.quick_ratio(), 3)
|
||||||
|
|
||||||
# If the url is stable and we did not set yet the match ratio and the
|
# If the url is stable and we did not set yet the match ratio and the
|
||||||
# current injected value changes the url page content
|
# current injected value changes the url page content
|
||||||
if kb.matchRatio is None:
|
if kb.matchRatio is None:
|
||||||
if (count or ratio >= LOWER_RATIO_BOUND) and ratio <= UPPER_RATIO_BOUND:
|
if ratio >= LOWER_RATIO_BOUND and ratio <= UPPER_RATIO_BOUND:
|
||||||
kb.matchRatio = ratio
|
kb.matchRatio = ratio
|
||||||
logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio)
|
logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio)
|
||||||
|
|
||||||
|
|||||||
+47
-14
@@ -32,7 +32,6 @@ from lib.core.agent import agent
|
|||||||
from lib.core.common import asciifyUrl
|
from lib.core.common import asciifyUrl
|
||||||
from lib.core.common import calculateDeltaSeconds
|
from lib.core.common import calculateDeltaSeconds
|
||||||
from lib.core.common import clearConsoleLine
|
from lib.core.common import clearConsoleLine
|
||||||
from lib.core.common import cpuThrottle
|
|
||||||
from lib.core.common import dataToStdout
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.common import evaluateCode
|
from lib.core.common import evaluateCode
|
||||||
from lib.core.common import extractRegexResult
|
from lib.core.common import extractRegexResult
|
||||||
@@ -123,7 +122,10 @@ class Connect(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _getPageProxy(**kwargs):
|
def _getPageProxy(**kwargs):
|
||||||
return Connect.getPage(**kwargs)
|
try:
|
||||||
|
return Connect.getPage(**kwargs)
|
||||||
|
except RuntimeError:
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _retryProxy(**kwargs):
|
def _retryProxy(**kwargs):
|
||||||
@@ -145,7 +147,7 @@ class Connect(object):
|
|||||||
warnMsg = "most probably web server instance hasn't recovered yet "
|
warnMsg = "most probably web server instance hasn't recovered yet "
|
||||||
warnMsg += "from previous timed based payload. If the problem "
|
warnMsg += "from previous timed based payload. If the problem "
|
||||||
warnMsg += "persists please wait for few minutes and rerun "
|
warnMsg += "persists please wait for few minutes and rerun "
|
||||||
warnMsg += "without flag T in option '--technique' "
|
warnMsg += "without flag 'T' in option '--technique' "
|
||||||
warnMsg += "(e.g. '--flush-session --technique=BEUS') or try to "
|
warnMsg += "(e.g. '--flush-session --technique=BEUS') or try to "
|
||||||
warnMsg += "lower the value of option '--time-sec' (e.g. '--time-sec=2')"
|
warnMsg += "lower the value of option '--time-sec' (e.g. '--time-sec=2')"
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
@@ -220,8 +222,6 @@ class Connect(object):
|
|||||||
|
|
||||||
if isinstance(conf.delay, (int, float)) and conf.delay > 0:
|
if isinstance(conf.delay, (int, float)) and conf.delay > 0:
|
||||||
time.sleep(conf.delay)
|
time.sleep(conf.delay)
|
||||||
elif conf.cpuThrottle:
|
|
||||||
cpuThrottle(conf.cpuThrottle)
|
|
||||||
|
|
||||||
if conf.offline:
|
if conf.offline:
|
||||||
return None, None, None
|
return None, None, None
|
||||||
@@ -376,6 +376,9 @@ class Connect(object):
|
|||||||
if boundary:
|
if boundary:
|
||||||
headers[HTTP_HEADER.CONTENT_TYPE] = "%s; boundary=%s" % (headers[HTTP_HEADER.CONTENT_TYPE], boundary)
|
headers[HTTP_HEADER.CONTENT_TYPE] = "%s; boundary=%s" % (headers[HTTP_HEADER.CONTENT_TYPE], boundary)
|
||||||
|
|
||||||
|
if conf.keepAlive:
|
||||||
|
headers[HTTP_HEADER.CONNECTION] = "keep-alive"
|
||||||
|
|
||||||
# Reset header values to original in case of provided request file
|
# Reset header values to original in case of provided request file
|
||||||
if target and conf.requestFile:
|
if target and conf.requestFile:
|
||||||
headers = OrderedDict(conf.httpHeaders)
|
headers = OrderedDict(conf.httpHeaders)
|
||||||
@@ -616,14 +619,21 @@ class Connect(object):
|
|||||||
elif "forcibly closed" in tbMsg or "Connection is already closed" in tbMsg:
|
elif "forcibly closed" in tbMsg or "Connection is already closed" in tbMsg:
|
||||||
warnMsg = "connection was forcibly closed by the target URL"
|
warnMsg = "connection was forcibly closed by the target URL"
|
||||||
elif "timed out" in tbMsg:
|
elif "timed out" in tbMsg:
|
||||||
singleTimeWarnMessage("turning off pre-connect mechanism because of connection time out(s)")
|
if not conf.disablePrecon:
|
||||||
conf.disablePrecon = True
|
singleTimeWarnMessage("turning off pre-connect mechanism because of connection time out(s)")
|
||||||
|
conf.disablePrecon = True
|
||||||
|
|
||||||
|
if kb.testMode and kb.testType not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED):
|
||||||
|
kb.responseTimes.clear()
|
||||||
|
|
||||||
if kb.testMode and kb.testType not in (None, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED):
|
if kb.testMode and kb.testType not in (None, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED):
|
||||||
singleTimeWarnMessage("there is a possibility that the target (or WAF) is dropping 'suspicious' requests")
|
singleTimeWarnMessage("there is a possibility that the target (or WAF) is dropping 'suspicious' requests")
|
||||||
warnMsg = "connection timed out to the target URL"
|
warnMsg = "connection timed out to the target URL"
|
||||||
elif "URLError" in tbMsg or "error" in tbMsg:
|
elif "URLError" in tbMsg or "error" in tbMsg:
|
||||||
warnMsg = "unable to connect to the target URL"
|
warnMsg = "unable to connect to the target URL"
|
||||||
|
match = re.search(r"Errno \d+\] ([^>]+)", tbMsg)
|
||||||
|
if match:
|
||||||
|
warnMsg += " ('%s')" % match.group(1).strip()
|
||||||
elif "NTLM" in tbMsg:
|
elif "NTLM" in tbMsg:
|
||||||
warnMsg = "there has been a problem with NTLM authentication"
|
warnMsg = "there has been a problem with NTLM authentication"
|
||||||
elif "BadStatusLine" in tbMsg:
|
elif "BadStatusLine" in tbMsg:
|
||||||
@@ -642,7 +652,7 @@ class Connect(object):
|
|||||||
else:
|
else:
|
||||||
warnMsg = "unable to connect to the target URL"
|
warnMsg = "unable to connect to the target URL"
|
||||||
|
|
||||||
if "BadStatusLine" not in tbMsg:
|
if "BadStatusLine" not in tbMsg and any((conf.proxy, conf.tor)):
|
||||||
warnMsg += " or proxy"
|
warnMsg += " or proxy"
|
||||||
|
|
||||||
if silent:
|
if silent:
|
||||||
@@ -789,9 +799,20 @@ class Connect(object):
|
|||||||
value = agent.replacePayload(value, payload)
|
value = agent.replacePayload(value, payload)
|
||||||
else:
|
else:
|
||||||
# GET, POST, URI and Cookie payload needs to be thoroughly URL encoded
|
# GET, POST, URI and Cookie payload needs to be thoroughly URL encoded
|
||||||
if place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and kb.postUrlEncode:
|
if (place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) or place == PLACE.CUSTOM_HEADER and value.split(',')[0] == HTTP_HEADER.COOKIE) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and kb.postUrlEncode:
|
||||||
payload = urlencode(payload, '%', False, place != PLACE.URI) # spaceplus is handled down below
|
skip = False
|
||||||
value = agent.replacePayload(value, payload)
|
|
||||||
|
if place == PLACE.COOKIE or place == PLACE.CUSTOM_HEADER and value.split(',')[0] == HTTP_HEADER.COOKIE:
|
||||||
|
if kb.cookieEncodeChoice is None:
|
||||||
|
msg = "do you want to URL encode cookie values (implementation specific)? %s" % ("[Y/n]" if not conf.url.endswith(".aspx") else "[y/N]") # Reference: https://support.microsoft.com/en-us/kb/313282
|
||||||
|
choice = readInput(msg, default='Y' if not conf.url.endswith(".aspx") else 'N')
|
||||||
|
kb.cookieEncodeChoice = choice.upper().strip() == "Y"
|
||||||
|
if not kb.cookieEncodeChoice:
|
||||||
|
skip = True
|
||||||
|
|
||||||
|
if not skip:
|
||||||
|
payload = urlencode(payload, '%', False, place != PLACE.URI) # spaceplus is handled down below
|
||||||
|
value = agent.replacePayload(value, payload)
|
||||||
|
|
||||||
if conf.hpp:
|
if conf.hpp:
|
||||||
if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_API.ASP, WEB_API.ASPX)):
|
if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_API.ASP, WEB_API.ASPX)):
|
||||||
@@ -828,9 +849,13 @@ class Connect(object):
|
|||||||
|
|
||||||
if PLACE.GET in conf.parameters:
|
if PLACE.GET in conf.parameters:
|
||||||
get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value
|
get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value
|
||||||
|
elif place == PLACE.GET: # Note: for (e.g.) checkWaf() when there are no GET parameters
|
||||||
|
get = value
|
||||||
|
|
||||||
if PLACE.POST in conf.parameters:
|
if PLACE.POST in conf.parameters:
|
||||||
post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value
|
post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value
|
||||||
|
elif place == PLACE.POST:
|
||||||
|
post = value
|
||||||
|
|
||||||
if PLACE.CUSTOM_POST in conf.parameters:
|
if PLACE.CUSTOM_POST in conf.parameters:
|
||||||
post = conf.parameters[PLACE.CUSTOM_POST].replace(CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value
|
post = conf.parameters[PLACE.CUSTOM_POST].replace(CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value
|
||||||
@@ -859,15 +884,23 @@ class Connect(object):
|
|||||||
if conf.csrfToken:
|
if conf.csrfToken:
|
||||||
def _adjustParameter(paramString, parameter, newValue):
|
def _adjustParameter(paramString, parameter, newValue):
|
||||||
retVal = paramString
|
retVal = paramString
|
||||||
match = re.search("%s=(?P<value>[^&]*)" % re.escape(parameter), paramString)
|
match = re.search("%s=[^&]*" % re.escape(parameter), paramString)
|
||||||
if match:
|
if match:
|
||||||
retVal = re.sub("%s=[^&]*" % re.escape(parameter), "%s=%s" % (parameter, newValue), paramString)
|
retVal = re.sub(match.group(0), "%s=%s" % (parameter, newValue), paramString)
|
||||||
|
else:
|
||||||
|
match = re.search("(%s[\"']:[\"'])([^\"']+)" % re.escape(parameter), paramString)
|
||||||
|
if match:
|
||||||
|
retVal = re.sub(match.group(0), "%s%s" % (match.group(1), newValue), paramString)
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.data if conf.csrfUrl == conf.url else None, method=conf.method if conf.csrfUrl == conf.url else None, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST))
|
page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.data if conf.csrfUrl == conf.url else None, method=conf.method if conf.csrfUrl == conf.url else None, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST))
|
||||||
match = re.search(r"<input[^>]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % re.escape(conf.csrfToken), page or "")
|
match = re.search(r"<input[^>]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % re.escape(conf.csrfToken), page or "")
|
||||||
token = (match.group(2) or match.group(3) or match.group(4)) if match else None
|
token = (match.group(2) or match.group(3) or match.group(4)) if match else None
|
||||||
|
|
||||||
|
if not token:
|
||||||
|
match = re.search(r"%s[\"']:[\"']([^\"']+)" % re.escape(conf.csrfToken), page or "")
|
||||||
|
token = match.group(1) if match else None
|
||||||
|
|
||||||
if not token:
|
if not token:
|
||||||
if conf.csrfUrl != conf.url and code == httplib.OK:
|
if conf.csrfUrl != conf.url and code == httplib.OK:
|
||||||
if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""):
|
if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""):
|
||||||
@@ -959,7 +992,7 @@ class Connect(object):
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
compiler.parse(conf.evalCode.replace(';', '\n'))
|
compiler.parse(unicodeencode(conf.evalCode.replace(';', '\n')))
|
||||||
except SyntaxError, ex:
|
except SyntaxError, ex:
|
||||||
original = replacement = ex.text.strip()
|
original = replacement = ex.text.strip()
|
||||||
for _ in re.findall(r"[A-Za-z_]+", original)[::-1]:
|
for _ in re.findall(r"[A-Za-z_]+", original)[::-1]:
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
|
|||||||
|
|
||||||
outputs = _goInferenceFields(expression, expressionFields, expressionFieldsList, payload, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump)
|
outputs = _goInferenceFields(expression, expressionFields, expressionFieldsList, payload, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump)
|
||||||
|
|
||||||
return ", ".join(output for output in outputs) if not isNoneValue(outputs) else None
|
return ", ".join(output or "" for output in outputs) if not isNoneValue(outputs) else None
|
||||||
|
|
||||||
def _goBooleanProxy(expression):
|
def _goBooleanProxy(expression):
|
||||||
"""
|
"""
|
||||||
@@ -432,7 +432,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
|||||||
found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE
|
found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE
|
||||||
|
|
||||||
if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found:
|
if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found:
|
||||||
kb.responseTimeMode = re.sub(r"(?i)[^a-z]", "", re.sub(r"'[^']+'", "", expression)) if re.search(r"(?i)SELECT.+FROM", expression) else None
|
kb.responseTimeMode = re.sub(r"(?i)[^a-z]", "", re.sub(r"'[^']+'", "", re.sub(r"(?i)(\w+)\(.+\)", r"\g<1>", expression))) if re.search(r"(?i)SELECT.+FROM", expression) else None
|
||||||
|
|
||||||
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
|
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
|
||||||
kb.technique = PAYLOAD.TECHNIQUE.TIME
|
kb.technique = PAYLOAD.TECHNIQUE.TIME
|
||||||
|
|||||||
+18
-2
@@ -6,6 +6,8 @@ See the file 'doc/COPYING' for copying permission
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from extra.icmpsh.icmpsh_m import main as icmpshmaster
|
from extra.icmpsh.icmpsh_m import main as icmpshmaster
|
||||||
@@ -54,15 +56,29 @@ class ICMPsh:
|
|||||||
if self.localIP:
|
if self.localIP:
|
||||||
message += "[Enter for '%s' (detected)] " % self.localIP
|
message += "[Enter for '%s' (detected)] " % self.localIP
|
||||||
|
|
||||||
while not address:
|
valid = None
|
||||||
address = readInput(message, default=self.localIP)
|
while not valid:
|
||||||
|
valid = True
|
||||||
|
address = readInput(message, default=self.localIP or "")
|
||||||
|
|
||||||
|
try:
|
||||||
|
socket.inet_aton(address)
|
||||||
|
except socket.error:
|
||||||
|
valid = False
|
||||||
|
finally:
|
||||||
|
valid = valid and re.search(r"\d+\.\d+\.\d+\.\d+", address) is not None
|
||||||
|
|
||||||
if conf.batch and not address:
|
if conf.batch and not address:
|
||||||
raise SqlmapDataException("local host address is missing")
|
raise SqlmapDataException("local host address is missing")
|
||||||
|
elif address and not valid:
|
||||||
|
warnMsg = "invalid local host address"
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return address
|
return address
|
||||||
|
|
||||||
def _prepareIngredients(self, encode=True):
|
def _prepareIngredients(self, encode=True):
|
||||||
|
self.localIP = getattr(self, "localIP", None)
|
||||||
|
self.remoteIP = getattr(self, "remoteIP", None)
|
||||||
self.lhostStr = ICMPsh._selectLhost(self)
|
self.lhostStr = ICMPsh._selectLhost(self)
|
||||||
self.rhostStr = ICMPsh._selectRhost(self)
|
self.rhostStr = ICMPsh._selectRhost(self)
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ See the file 'doc/COPYING' for copying permission
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import select
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
@@ -47,8 +48,6 @@ from lib.core.subprocessng import recv_some
|
|||||||
|
|
||||||
if IS_WIN:
|
if IS_WIN:
|
||||||
import msvcrt
|
import msvcrt
|
||||||
else:
|
|
||||||
from select import select
|
|
||||||
|
|
||||||
class Metasploit:
|
class Metasploit:
|
||||||
"""
|
"""
|
||||||
@@ -550,7 +549,7 @@ class Metasploit:
|
|||||||
# Probably the child has exited
|
# Probably the child has exited
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
ready_fds = select([stdin_fd], [], [], 1)
|
ready_fds = select.select([stdin_fd], [], [], 1)
|
||||||
|
|
||||||
if stdin_fd in ready_fds[0]:
|
if stdin_fd in ready_fds[0]:
|
||||||
try:
|
try:
|
||||||
@@ -598,7 +597,7 @@ class Metasploit:
|
|||||||
else:
|
else:
|
||||||
proc.kill()
|
proc.kill()
|
||||||
|
|
||||||
except (EOFError, IOError):
|
except (EOFError, IOError, select.error):
|
||||||
return proc.returncode
|
return proc.returncode
|
||||||
|
|
||||||
def createMsfShellcode(self, exitfunc, format, extra, encode):
|
def createMsfShellcode(self, exitfunc, format, extra, encode):
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class Xp_cmdshell:
|
|||||||
def _xpCmdshellCreate(self):
|
def _xpCmdshellCreate(self):
|
||||||
cmd = ""
|
cmd = ""
|
||||||
|
|
||||||
if Backend.isVersionWithin(("2005", "2008", "2012")):
|
if not Backend.isVersionWithin(("2000",)):
|
||||||
logger.debug("activating sp_OACreate")
|
logger.debug("activating sp_OACreate")
|
||||||
|
|
||||||
cmd = getSQLSnippet(DBMS.MSSQL, "activate_sp_oacreate")
|
cmd = getSQLSnippet(DBMS.MSSQL, "activate_sp_oacreate")
|
||||||
@@ -56,7 +56,7 @@ class Xp_cmdshell:
|
|||||||
|
|
||||||
cmd = getSQLSnippet(DBMS.MSSQL, "create_new_xp_cmdshell", RANDSTR=self._randStr)
|
cmd = getSQLSnippet(DBMS.MSSQL, "create_new_xp_cmdshell", RANDSTR=self._randStr)
|
||||||
|
|
||||||
if Backend.isVersionWithin(("2005", "2008")):
|
if not Backend.isVersionWithin(("2000",)):
|
||||||
cmd += ";RECONFIGURE WITH OVERRIDE"
|
cmd += ";RECONFIGURE WITH OVERRIDE"
|
||||||
|
|
||||||
inject.goStacked(agent.runAsDBMSUser(cmd))
|
inject.goStacked(agent.runAsDBMSUser(cmd))
|
||||||
@@ -83,10 +83,10 @@ class Xp_cmdshell:
|
|||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
def _xpCmdshellConfigure(self, mode):
|
def _xpCmdshellConfigure(self, mode):
|
||||||
if Backend.isVersionWithin(("2005", "2008")):
|
if Backend.isVersionWithin(("2000",)):
|
||||||
cmd = self._xpCmdshellConfigure2005(mode)
|
|
||||||
else:
|
|
||||||
cmd = self._xpCmdshellConfigure2000(mode)
|
cmd = self._xpCmdshellConfigure2000(mode)
|
||||||
|
else:
|
||||||
|
cmd = self._xpCmdshellConfigure2005(mode)
|
||||||
|
|
||||||
inject.goStacked(agent.runAsDBMSUser(cmd))
|
inject.goStacked(agent.runAsDBMSUser(cmd))
|
||||||
|
|
||||||
@@ -111,8 +111,8 @@ class Xp_cmdshell:
|
|||||||
errMsg += "storing console output within the back-end file system "
|
errMsg += "storing console output within the back-end file system "
|
||||||
errMsg += "does not have writing permissions for the DBMS process. "
|
errMsg += "does not have writing permissions for the DBMS process. "
|
||||||
errMsg += "You are advised to manually adjust it with option "
|
errMsg += "You are advised to manually adjust it with option "
|
||||||
errMsg += "--tmp-path switch or you will not be able to retrieve "
|
errMsg += "'--tmp-path' or you won't be able to retrieve "
|
||||||
errMsg += "the commands output"
|
errMsg += "the command(s) output"
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
elif isNoneValue(output):
|
elif isNoneValue(output):
|
||||||
logger.error("unable to retrieve xp_cmdshell output")
|
logger.error("unable to retrieve xp_cmdshell output")
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from extra.safe2bin.safe2bin import safechardecode
|
|
||||||
from extra.safe2bin.safe2bin import safecharencode
|
from extra.safe2bin.safe2bin import safecharencode
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
@@ -20,13 +18,11 @@ from lib.core.common import decodeIntToUnicode
|
|||||||
from lib.core.common import filterControlChars
|
from lib.core.common import filterControlChars
|
||||||
from lib.core.common import getCharset
|
from lib.core.common import getCharset
|
||||||
from lib.core.common import getCounter
|
from lib.core.common import getCounter
|
||||||
from lib.core.common import getUnicode
|
|
||||||
from lib.core.common import goGoodSamaritan
|
from lib.core.common import goGoodSamaritan
|
||||||
from lib.core.common import getPartRun
|
from lib.core.common import getPartRun
|
||||||
from lib.core.common import hashDBRetrieve
|
from lib.core.common import hashDBRetrieve
|
||||||
from lib.core.common import hashDBWrite
|
from lib.core.common import hashDBWrite
|
||||||
from lib.core.common import incrementCounter
|
from lib.core.common import incrementCounter
|
||||||
from lib.core.common import randomInt
|
|
||||||
from lib.core.common import safeStringFormat
|
from lib.core.common import safeStringFormat
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
@@ -44,7 +40,6 @@ from lib.core.settings import INFERENCE_UNKNOWN_CHAR
|
|||||||
from lib.core.settings import INFERENCE_GREATER_CHAR
|
from lib.core.settings import INFERENCE_GREATER_CHAR
|
||||||
from lib.core.settings import INFERENCE_EQUALS_CHAR
|
from lib.core.settings import INFERENCE_EQUALS_CHAR
|
||||||
from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
|
from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
|
||||||
from lib.core.settings import MIN_TIME_RESPONSES
|
|
||||||
from lib.core.settings import MAX_BISECTION_LENGTH
|
from lib.core.settings import MAX_BISECTION_LENGTH
|
||||||
from lib.core.settings import MAX_TIME_REVALIDATION_STEPS
|
from lib.core.settings import MAX_TIME_REVALIDATION_STEPS
|
||||||
from lib.core.settings import NULL
|
from lib.core.settings import NULL
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from lib.core.common import calculateDeltaSeconds
|
|||||||
from lib.core.common import dataToStdout
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.common import decodeHexValue
|
from lib.core.common import decodeHexValue
|
||||||
from lib.core.common import extractRegexResult
|
from lib.core.common import extractRegexResult
|
||||||
|
from lib.core.common import getConsoleWidth
|
||||||
from lib.core.common import getPartRun
|
from lib.core.common import getPartRun
|
||||||
from lib.core.common import getUnicode
|
from lib.core.common import getUnicode
|
||||||
from lib.core.common import hashDBRetrieve
|
from lib.core.common import hashDBRetrieve
|
||||||
@@ -43,6 +44,7 @@ from lib.core.settings import MIN_ERROR_CHUNK_LENGTH
|
|||||||
from lib.core.settings import MAX_ERROR_CHUNK_LENGTH
|
from lib.core.settings import MAX_ERROR_CHUNK_LENGTH
|
||||||
from lib.core.settings import NULL
|
from lib.core.settings import NULL
|
||||||
from lib.core.settings import PARTIAL_VALUE_MARKER
|
from lib.core.settings import PARTIAL_VALUE_MARKER
|
||||||
|
from lib.core.settings import ROTATING_CHARS
|
||||||
from lib.core.settings import SLOW_ORDER_COUNT_THRESHOLD
|
from lib.core.settings import SLOW_ORDER_COUNT_THRESHOLD
|
||||||
from lib.core.settings import SQL_SCALAR_REGEX
|
from lib.core.settings import SQL_SCALAR_REGEX
|
||||||
from lib.core.settings import TURN_OFF_RESUME_INFO_LIMIT
|
from lib.core.settings import TURN_OFF_RESUME_INFO_LIMIT
|
||||||
@@ -54,6 +56,7 @@ from lib.utils.progress import ProgressBar
|
|||||||
|
|
||||||
def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
||||||
offset = 1
|
offset = 1
|
||||||
|
rotator = 0
|
||||||
partialValue = None
|
partialValue = None
|
||||||
threadData = getCurrentThreadData()
|
threadData = getCurrentThreadData()
|
||||||
retVal = hashDBRetrieve(expression, checkConf=True)
|
retVal = hashDBRetrieve(expression, checkConf=True)
|
||||||
@@ -173,8 +176,16 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
if kb.fileReadMode and output:
|
if output:
|
||||||
dataToStdout(_formatPartialContent(output).replace(r"\n", "\n").replace(r"\t", "\t"))
|
if kb.fileReadMode:
|
||||||
|
dataToStdout(_formatPartialContent(output).replace(r"\n", "\n").replace(r"\t", "\t"))
|
||||||
|
elif offset > 1:
|
||||||
|
rotator += 1
|
||||||
|
|
||||||
|
if rotator >= len(ROTATING_CHARS):
|
||||||
|
rotator = 0
|
||||||
|
|
||||||
|
dataToStdout("\r%s\r" % ROTATING_CHARS[rotator])
|
||||||
else:
|
else:
|
||||||
retVal = output
|
retVal = output
|
||||||
break
|
break
|
||||||
@@ -203,6 +214,7 @@ def _errorFields(expression, expressionFields, expressionFieldsList, num=None, e
|
|||||||
values = []
|
values = []
|
||||||
origExpr = None
|
origExpr = None
|
||||||
|
|
||||||
|
width = getConsoleWidth()
|
||||||
threadData = getCurrentThreadData()
|
threadData = getCurrentThreadData()
|
||||||
|
|
||||||
for field in expressionFieldsList:
|
for field in expressionFieldsList:
|
||||||
@@ -229,7 +241,12 @@ def _errorFields(expression, expressionFields, expressionFieldsList, num=None, e
|
|||||||
if kb.fileReadMode and output and output.strip():
|
if kb.fileReadMode and output and output.strip():
|
||||||
print
|
print
|
||||||
elif output is not None and not (threadData.resumed and kb.suppressResumeInfo) and not (emptyFields and field in emptyFields):
|
elif output is not None and not (threadData.resumed and kb.suppressResumeInfo) and not (emptyFields and field in emptyFields):
|
||||||
dataToStdout("[%s] [INFO] %s: %s\n" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", safecharencode(output)))
|
status = "[%s] [INFO] %s: %s" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", output if kb.safeCharEncode else safecharencode(output))
|
||||||
|
|
||||||
|
if len(status) > width:
|
||||||
|
status = "%s..." % status[:width - 3]
|
||||||
|
|
||||||
|
dataToStdout("%s\n" % status)
|
||||||
|
|
||||||
if isinstance(num, int):
|
if isinstance(num, int):
|
||||||
expression = origExpr
|
expression = origExpr
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
|
|||||||
query = agent.suffixQuery(query, suffix=suffix, comment=comment)
|
query = agent.suffixQuery(query, suffix=suffix, comment=comment)
|
||||||
payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where)
|
payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where)
|
||||||
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
|
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
|
||||||
return not re.search(r"(warning|error|order by|failed)", page or "", re.I) and comparison(page, headers) or re.search(r"data types cannot be compared or sorted", page or "", re.I)
|
return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order by", "unknown column", "failed")) and comparison(page, headers) or re.search(r"data types cannot be compared or sorted", page or "", re.I)
|
||||||
|
|
||||||
if _orderByTest(1) and not _orderByTest(randomInt()):
|
if _orderByTest(1) and not _orderByTest(randomInt()):
|
||||||
infoMsg = "ORDER BY technique seems to be usable. "
|
infoMsg = "'ORDER BY' technique appears to be usable. "
|
||||||
infoMsg += "This should reduce the time needed "
|
infoMsg += "This should reduce the time needed "
|
||||||
infoMsg += "to find the right number "
|
infoMsg += "to find the right number "
|
||||||
infoMsg += "of query columns. Automatically extending the "
|
infoMsg += "of query columns. Automatically extending the "
|
||||||
|
|||||||
@@ -328,12 +328,13 @@ def unionUse(expression, unpack=True, dump=False):
|
|||||||
del threadData.shared.buffered[0]
|
del threadData.shared.buffered[0]
|
||||||
|
|
||||||
if conf.verbose == 1 and not (threadData.resumed and kb.suppressResumeInfo) and not threadData.shared.showEta:
|
if conf.verbose == 1 and not (threadData.resumed and kb.suppressResumeInfo) and not threadData.shared.showEta:
|
||||||
status = "[%s] [INFO] %s: %s" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", safecharencode(",".join("\"%s\"" % _ for _ in flattenValue(arrayizeValue(items))) if not isinstance(items, basestring) else items))
|
_ = ",".join("\"%s\"" % _ for _ in flattenValue(arrayizeValue(items))) if not isinstance(items, basestring) else items
|
||||||
|
status = "[%s] [INFO] %s: %s" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", _ if kb.safeCharEncode else safecharencode(_))
|
||||||
|
|
||||||
if len(status) > width:
|
if len(status) > width:
|
||||||
status = "%s..." % status[:width - 3]
|
status = "%s..." % status[:width - 3]
|
||||||
|
|
||||||
dataToStdout("%s\n" % status, True)
|
dataToStdout("%s\n" % status)
|
||||||
|
|
||||||
runThreads(numThreads, unionThread)
|
runThreads(numThreads, unionThread)
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -31,6 +31,7 @@ from lib.core.data import logger
|
|||||||
from lib.core.datatype import AttribDict
|
from lib.core.datatype import AttribDict
|
||||||
from lib.core.defaults import _defaults
|
from lib.core.defaults import _defaults
|
||||||
from lib.core.enums import CONTENT_STATUS
|
from lib.core.enums import CONTENT_STATUS
|
||||||
|
from lib.core.enums import MKSTEMP_PREFIX
|
||||||
from lib.core.enums import PART_RUN_CONTENT_TYPES
|
from lib.core.enums import PART_RUN_CONTENT_TYPES
|
||||||
from lib.core.exception import SqlmapConnectionException
|
from lib.core.exception import SqlmapConnectionException
|
||||||
from lib.core.log import LOGGER_HANDLER
|
from lib.core.log import LOGGER_HANDLER
|
||||||
@@ -643,7 +644,7 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST
|
|||||||
REST-JSON API server
|
REST-JSON API server
|
||||||
"""
|
"""
|
||||||
DataStore.admin_id = hexencode(os.urandom(16))
|
DataStore.admin_id = hexencode(os.urandom(16))
|
||||||
Database.filepath = tempfile.mkstemp(prefix="sqlmapipc-", text=False)[1]
|
Database.filepath = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.IPC, text=False)[1]
|
||||||
|
|
||||||
logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port))
|
logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port))
|
||||||
logger.info("Admin ID: %s" % DataStore.admin_id)
|
logger.info("Admin ID: %s" % DataStore.admin_id)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from lib.core.common import safeCSValue
|
|||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
|
from lib.core.enums import MKSTEMP_PREFIX
|
||||||
from lib.core.exception import SqlmapConnectionException
|
from lib.core.exception import SqlmapConnectionException
|
||||||
from lib.core.exception import SqlmapSyntaxException
|
from lib.core.exception import SqlmapSyntaxException
|
||||||
from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS
|
from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS
|
||||||
@@ -198,7 +199,7 @@ def storeResultsToFile(results):
|
|||||||
kb.storeCrawlingChoice = test[0] in ("y", "Y")
|
kb.storeCrawlingChoice = test[0] in ("y", "Y")
|
||||||
|
|
||||||
if kb.storeCrawlingChoice:
|
if kb.storeCrawlingChoice:
|
||||||
handle, filename = tempfile.mkstemp(prefix="sqlmapcrawling-", suffix=".csv" if conf.forms else ".txt")
|
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CRAWLER, suffix=".csv" if conf.forms else ".txt")
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
|
|
||||||
infoMsg = "writing crawling results to a temporary file '%s' " % filename
|
infoMsg = "writing crawling results to a temporary file '%s' " % filename
|
||||||
|
|||||||
+14
-2
@@ -30,6 +30,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
import zipfile
|
||||||
|
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
@@ -45,6 +46,7 @@ from lib.core.common import dataToStdout
|
|||||||
from lib.core.common import getFileItems
|
from lib.core.common import getFileItems
|
||||||
from lib.core.common import getPublicTypeMembers
|
from lib.core.common import getPublicTypeMembers
|
||||||
from lib.core.common import getSafeExString
|
from lib.core.common import getSafeExString
|
||||||
|
from lib.core.common import getUnicode
|
||||||
from lib.core.common import hashDBRetrieve
|
from lib.core.common import hashDBRetrieve
|
||||||
from lib.core.common import hashDBWrite
|
from lib.core.common import hashDBWrite
|
||||||
from lib.core.common import normalizeUnicode
|
from lib.core.common import normalizeUnicode
|
||||||
@@ -60,6 +62,8 @@ from lib.core.data import kb
|
|||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
from lib.core.enums import HASH
|
from lib.core.enums import HASH
|
||||||
|
from lib.core.enums import MKSTEMP_PREFIX
|
||||||
|
from lib.core.exception import SqlmapDataException
|
||||||
from lib.core.exception import SqlmapUserQuitException
|
from lib.core.exception import SqlmapUserQuitException
|
||||||
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
|
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
|
||||||
from lib.core.settings import COMMON_USER_COLUMNS
|
from lib.core.settings import COMMON_USER_COLUMNS
|
||||||
@@ -384,7 +388,7 @@ def storeHashesToFile(attack_dict):
|
|||||||
if not kb.storeHashesChoice:
|
if not kb.storeHashesChoice:
|
||||||
return
|
return
|
||||||
|
|
||||||
handle, filename = tempfile.mkstemp(prefix="sqlmaphashes-", suffix=".txt")
|
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.HASHES, suffix=".txt")
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
|
|
||||||
infoMsg = "writing hashes to a temporary file '%s' " % filename
|
infoMsg = "writing hashes to a temporary file '%s' " % filename
|
||||||
@@ -501,7 +505,7 @@ def attackDumpedTable():
|
|||||||
value = table[column]['values'][i]
|
value = table[column]['values'][i]
|
||||||
|
|
||||||
if value and value.lower() in lut:
|
if value and value.lower() in lut:
|
||||||
table[column]['values'][i] += " (%s)" % lut[value.lower()]
|
table[column]['values'][i] = "%s (%s)" % (getUnicode(table[column]['values'][i]), getUnicode(lut[value.lower()]))
|
||||||
table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i]))
|
table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i]))
|
||||||
|
|
||||||
def hashRecognition(value):
|
def hashRecognition(value):
|
||||||
@@ -785,6 +789,14 @@ def dictionaryAttack(attack_dict):
|
|||||||
for dictPath in dictPaths:
|
for dictPath in dictPaths:
|
||||||
checkFile(dictPath)
|
checkFile(dictPath)
|
||||||
|
|
||||||
|
if os.path.splitext(dictPath)[1].lower() == ".zip":
|
||||||
|
_ = zipfile.ZipFile(dictPath, 'r')
|
||||||
|
if len(_.namelist()) == 0:
|
||||||
|
errMsg = "no file(s) inside '%s'" % dictPath
|
||||||
|
raise SqlmapDataException(errMsg)
|
||||||
|
else:
|
||||||
|
_.open(_.namelist()[0])
|
||||||
|
|
||||||
kb.wordlists = dictPaths
|
kb.wordlists = dictPaths
|
||||||
|
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
|
|||||||
+1
-1
@@ -66,7 +66,7 @@ class HashDB(object):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def hashKey(key):
|
def hashKey(key):
|
||||||
key = key.encode(UNICODE_ENCODING) if isinstance(key, unicode) else repr(key)
|
key = key.encode(UNICODE_ENCODING) if isinstance(key, unicode) else repr(key)
|
||||||
retVal = int(hashlib.md5(key).hexdigest()[:12], 16)
|
retVal = int(hashlib.md5(key).hexdigest(), 16) & 0x7fffffffffffffff # Reference: http://stackoverflow.com/a/4448400
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
def retrieve(self, key, unserialize=False):
|
def retrieve(self, key, unserialize=False):
|
||||||
|
|||||||
@@ -11,14 +11,17 @@ from extra.safe2bin.safe2bin import safechardecode
|
|||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.bigarray import BigArray
|
from lib.core.bigarray import BigArray
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
|
from lib.core.common import getUnicode
|
||||||
from lib.core.common import isNoneValue
|
from lib.core.common import isNoneValue
|
||||||
from lib.core.common import isNumPosStrValue
|
from lib.core.common import isNumPosStrValue
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
from lib.core.common import unArrayizeValue
|
from lib.core.common import unArrayizeValue
|
||||||
from lib.core.common import unsafeSQLIdentificatorNaming
|
from lib.core.common import unsafeSQLIdentificatorNaming
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
|
from lib.core.dicts import DUMP_REPLACEMENTS
|
||||||
from lib.core.enums import CHARSET_TYPE
|
from lib.core.enums import CHARSET_TYPE
|
||||||
from lib.core.enums import EXPECTED
|
from lib.core.enums import EXPECTED
|
||||||
from lib.core.exception import SqlmapConnectionException
|
from lib.core.exception import SqlmapConnectionException
|
||||||
@@ -134,10 +137,13 @@ def pivotDumpTable(table, colList, count=None, blind=True):
|
|||||||
value = _(column, pivotValue)
|
value = _(column, pivotValue)
|
||||||
if column == colList[0]:
|
if column == colList[0]:
|
||||||
if isNoneValue(value):
|
if isNoneValue(value):
|
||||||
for pivotValue in filter(None, (" " if pivotValue == " " else None, "%s%s" % (pivotValue[0], unichr(ord(pivotValue[1]) + 1)) if len(pivotValue) > 1 else None, unichr(ord(pivotValue[0]) + 1))):
|
try:
|
||||||
value = _(column, pivotValue)
|
for pivotValue in filter(None, (" " if pivotValue == " " else None, "%s%s" % (pivotValue[0], unichr(ord(pivotValue[1]) + 1)) if len(pivotValue) > 1 else None, unichr(ord(pivotValue[0]) + 1))):
|
||||||
if not isNoneValue(value):
|
value = _(column, pivotValue)
|
||||||
break
|
if not isNoneValue(value):
|
||||||
|
break
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
if isNoneValue(value):
|
if isNoneValue(value):
|
||||||
breakRetrieval = True
|
breakRetrieval = True
|
||||||
@@ -156,10 +162,12 @@ def pivotDumpTable(table, colList, count=None, blind=True):
|
|||||||
|
|
||||||
value = "" if isNoneValue(value) else unArrayizeValue(value)
|
value = "" if isNoneValue(value) else unArrayizeValue(value)
|
||||||
|
|
||||||
lengths[column] = max(lengths[column], len(value) if value else 0)
|
lengths[column] = max(lengths[column], len(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value))))
|
||||||
entries[column].append(value)
|
entries[column].append(value)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
kb.dumpKeyboardInterrupt = True
|
||||||
|
|
||||||
warnMsg = "user aborted during enumeration. sqlmap "
|
warnMsg = "user aborted during enumeration. sqlmap "
|
||||||
warnMsg += "will display partial output"
|
warnMsg += "will display partial output"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import cookielib
|
|
||||||
import httplib
|
import httplib
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
@@ -26,7 +25,6 @@ from lib.core.enums import HTTP_HEADER
|
|||||||
from lib.core.enums import REDIRECTION
|
from lib.core.enums import REDIRECTION
|
||||||
from lib.core.exception import SqlmapBaseException
|
from lib.core.exception import SqlmapBaseException
|
||||||
from lib.core.exception import SqlmapConnectionException
|
from lib.core.exception import SqlmapConnectionException
|
||||||
from lib.core.exception import SqlmapGenericException
|
|
||||||
from lib.core.exception import SqlmapUserQuitException
|
from lib.core.exception import SqlmapUserQuitException
|
||||||
from lib.core.settings import DUMMY_SEARCH_USER_AGENT
|
from lib.core.settings import DUMMY_SEARCH_USER_AGENT
|
||||||
from lib.core.settings import DUCKDUCKGO_REGEX
|
from lib.core.settings import DUCKDUCKGO_REGEX
|
||||||
@@ -35,7 +33,6 @@ from lib.core.settings import GOOGLE_REGEX
|
|||||||
from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE
|
from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
from lib.request.basic import decodePage
|
from lib.request.basic import decodePage
|
||||||
from lib.request.httpshandler import HTTPSHandler
|
|
||||||
from thirdparty.socks import socks
|
from thirdparty.socks import socks
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -106,12 +106,6 @@ class Fingerprint(GenericFingerprint):
|
|||||||
if not conf.extensiveFp and (Backend.isDbmsWithin(FIREBIRD_ALIASES) \
|
if not conf.extensiveFp and (Backend.isDbmsWithin(FIREBIRD_ALIASES) \
|
||||||
or (conf.dbms or "").lower() in FIREBIRD_ALIASES) and Backend.getVersion() and \
|
or (conf.dbms or "").lower() in FIREBIRD_ALIASES) and Backend.getVersion() and \
|
||||||
Backend.getVersion() != UNKNOWN_DBMS_VERSION:
|
Backend.getVersion() != UNKNOWN_DBMS_VERSION:
|
||||||
v = Backend.getVersion().replace(">", "")
|
|
||||||
v = v.replace("=", "")
|
|
||||||
v = v.replace(" ", "")
|
|
||||||
|
|
||||||
Backend.setVersion(v)
|
|
||||||
|
|
||||||
setDbms("%s %s" % (DBMS.FIREBIRD, Backend.getVersion()))
|
setDbms("%s %s" % (DBMS.FIREBIRD, Backend.getVersion()))
|
||||||
|
|
||||||
self.getBanner()
|
self.getBanner()
|
||||||
|
|||||||
@@ -83,12 +83,6 @@ class Fingerprint(GenericFingerprint):
|
|||||||
if not conf.extensiveFp and (Backend.isDbmsWithin(HSQLDB_ALIASES) \
|
if not conf.extensiveFp and (Backend.isDbmsWithin(HSQLDB_ALIASES) \
|
||||||
or (conf.dbms or "").lower() in HSQLDB_ALIASES) and Backend.getVersion() and \
|
or (conf.dbms or "").lower() in HSQLDB_ALIASES) and Backend.getVersion() and \
|
||||||
Backend.getVersion() != UNKNOWN_DBMS_VERSION:
|
Backend.getVersion() != UNKNOWN_DBMS_VERSION:
|
||||||
v = Backend.getVersion().replace(">", "")
|
|
||||||
v = v.replace("=", "")
|
|
||||||
v = v.replace(" ", "")
|
|
||||||
|
|
||||||
Backend.setVersion(v)
|
|
||||||
|
|
||||||
setDbms("%s %s" % (DBMS.HSQLDB, Backend.getVersion()))
|
setDbms("%s %s" % (DBMS.HSQLDB, Backend.getVersion()))
|
||||||
|
|
||||||
if Backend.isVersionGreaterOrEqualThan("1.7.2"):
|
if Backend.isVersionGreaterOrEqualThan("1.7.2"):
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Connector(GenericConnector):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout)
|
self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout)
|
||||||
except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg:
|
except (pymssql.Error, _mssql.MssqlDatabaseException), msg:
|
||||||
raise SqlmapConnectionException(msg)
|
raise SqlmapConnectionException(msg)
|
||||||
|
|
||||||
self.initCursor()
|
self.initCursor()
|
||||||
@@ -50,7 +50,7 @@ class Connector(GenericConnector):
|
|||||||
def fetchall(self):
|
def fetchall(self):
|
||||||
try:
|
try:
|
||||||
return self.cursor.fetchall()
|
return self.cursor.fetchall()
|
||||||
except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg:
|
except (pymssql.Error, _mssql.MssqlDatabaseException), msg:
|
||||||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % str(msg).replace("\n", " "))
|
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % str(msg).replace("\n", " "))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,9 @@ class Fingerprint(GenericFingerprint):
|
|||||||
for version, check in (("2000", "HOST_NAME()=HOST_NAME()"), \
|
for version, check in (("2000", "HOST_NAME()=HOST_NAME()"), \
|
||||||
("2005", "XACT_STATE()=XACT_STATE()"), \
|
("2005", "XACT_STATE()=XACT_STATE()"), \
|
||||||
("2008", "SYSDATETIME()=SYSDATETIME()"), \
|
("2008", "SYSDATETIME()=SYSDATETIME()"), \
|
||||||
("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)")):
|
("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), \
|
||||||
|
("2014", "CHARINDEX('12.0.2000',@@version)>0"), \
|
||||||
|
("2016", "ISJSON(NULL) IS NULL")):
|
||||||
result = inject.checkBooleanExpression(check)
|
result = inject.checkBooleanExpression(check)
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ import re
|
|||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
from lib.core.common import Format
|
from lib.core.common import Format
|
||||||
from lib.core.common import getUnicode
|
from lib.core.common import getUnicode
|
||||||
|
from lib.core.common import hashDBRetrieve
|
||||||
|
from lib.core.common import hashDBWrite
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
|
from lib.core.enums import HASHDB_KEYS
|
||||||
from lib.core.enums import OS
|
from lib.core.enums import OS
|
||||||
from lib.core.session import setDbms
|
from lib.core.session import setDbms
|
||||||
from lib.core.settings import MYSQL_ALIASES
|
from lib.core.settings import MYSQL_ALIASES
|
||||||
@@ -37,17 +40,18 @@ class Fingerprint(GenericFingerprint):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# MySQL valid versions updated on 04/2011
|
# Reference: https://downloads.mysql.com/archives/community/
|
||||||
versions = (
|
versions = (
|
||||||
(32200, 32235), # MySQL 3.22
|
(32200, 32235), # MySQL 3.22
|
||||||
(32300, 32359), # MySQL 3.23
|
(32300, 32359), # MySQL 3.23
|
||||||
(40000, 40032), # MySQL 4.0
|
(40000, 40032), # MySQL 4.0
|
||||||
(40100, 40131), # MySQL 4.1
|
(40100, 40131), # MySQL 4.1
|
||||||
(50000, 50092), # MySQL 5.0
|
(50000, 50092), # MySQL 5.0
|
||||||
(50100, 50156), # MySQL 5.1
|
(50100, 50172), # MySQL 5.1
|
||||||
(50400, 50404), # MySQL 5.4
|
(50400, 50404), # MySQL 5.4
|
||||||
(50500, 50521), # MySQL 5.5
|
(50500, 50549), # MySQL 5.5
|
||||||
(50600, 50604), # MySQL 5.6
|
(50600, 50630), # MySQL 5.6
|
||||||
|
(50700, 50712), # MySQL 5.7
|
||||||
(60000, 60014), # MySQL 6.0
|
(60000, 60014), # MySQL 6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -103,6 +107,10 @@ class Fingerprint(GenericFingerprint):
|
|||||||
value += "back-end DBMS: "
|
value += "back-end DBMS: "
|
||||||
actVer = Format.getDbms()
|
actVer = Format.getDbms()
|
||||||
|
|
||||||
|
_ = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK)
|
||||||
|
if _:
|
||||||
|
actVer += " (%s fork)" % _
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
value += actVer
|
value += actVer
|
||||||
return value
|
return value
|
||||||
@@ -145,12 +153,6 @@ class Fingerprint(GenericFingerprint):
|
|||||||
if not conf.extensiveFp and (Backend.isDbmsWithin(MYSQL_ALIASES) \
|
if not conf.extensiveFp and (Backend.isDbmsWithin(MYSQL_ALIASES) \
|
||||||
or (conf.dbms or "").lower() in MYSQL_ALIASES) and Backend.getVersion() and \
|
or (conf.dbms or "").lower() in MYSQL_ALIASES) and Backend.getVersion() and \
|
||||||
Backend.getVersion() != UNKNOWN_DBMS_VERSION:
|
Backend.getVersion() != UNKNOWN_DBMS_VERSION:
|
||||||
v = Backend.getVersion().replace(">", "")
|
|
||||||
v = v.replace("=", "")
|
|
||||||
v = v.replace(" ", "")
|
|
||||||
|
|
||||||
Backend.setVersion(v)
|
|
||||||
|
|
||||||
setDbms("%s %s" % (DBMS.MYSQL, Backend.getVersion()))
|
setDbms("%s %s" % (DBMS.MYSQL, Backend.getVersion()))
|
||||||
|
|
||||||
if Backend.isVersionGreaterOrEqualThan("5"):
|
if Backend.isVersionGreaterOrEqualThan("5"):
|
||||||
@@ -177,6 +179,9 @@ class Fingerprint(GenericFingerprint):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) is None:
|
||||||
|
hashDBWrite(HASHDB_KEYS.DBMS_FORK, inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'") and "MariaDB" or "")
|
||||||
|
|
||||||
# reading information_schema on some platforms is causing annoying timeout exits
|
# reading information_schema on some platforms is causing annoying timeout exits
|
||||||
# Reference: http://bugs.mysql.com/bug.php?id=15855
|
# Reference: http://bugs.mysql.com/bug.php?id=15855
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ class Fingerprint(GenericFingerprint):
|
|||||||
infoMsg = "actively fingerprinting %s" % DBMS.ORACLE
|
infoMsg = "actively fingerprinting %s" % DBMS.ORACLE
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
for version in ("11i", "10g", "9i", "8i"):
|
# Reference: https://en.wikipedia.org/wiki/Oracle_Database
|
||||||
|
for version in ("12c", "11g", "10g", "9i", "8i"):
|
||||||
number = int(re.search("([\d]+)", version).group(1))
|
number = int(re.search("([\d]+)", version).group(1))
|
||||||
output = inject.checkBooleanExpression("%d=(SELECT SUBSTR((VERSION),1,%d) FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1)" % (number, 1 if number < 10 else 2))
|
output = inject.checkBooleanExpression("%d=(SELECT SUBSTR((VERSION),1,%d) FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1)" % (number, 1 if number < 10 else 2))
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Connector(GenericConnector):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout)
|
self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout)
|
||||||
except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg:
|
except (pymssql.Error, _mssql.MssqlDatabaseException), msg:
|
||||||
raise SqlmapConnectionException(msg)
|
raise SqlmapConnectionException(msg)
|
||||||
|
|
||||||
self.initCursor()
|
self.initCursor()
|
||||||
@@ -50,7 +50,7 @@ class Connector(GenericConnector):
|
|||||||
def fetchall(self):
|
def fetchall(self):
|
||||||
try:
|
try:
|
||||||
return self.cursor.fetchall()
|
return self.cursor.fetchall()
|
||||||
except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg:
|
except (pymssql.Error, _mssql.MssqlDatabaseException), msg:
|
||||||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % str(msg).replace("\n", " "))
|
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % str(msg).replace("\n", " "))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ class Databases:
|
|||||||
|
|
||||||
elif Backend.isDbms(DBMS.ACCESS):
|
elif Backend.isDbms(DBMS.ACCESS):
|
||||||
errMsg = "cannot retrieve column names, "
|
errMsg = "cannot retrieve column names, "
|
||||||
errMsg += "back-end DBMS is Access"
|
errMsg += "back-end DBMS is %s" % DBMS.ACCESS
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
bruteForce = True
|
bruteForce = True
|
||||||
|
|
||||||
@@ -572,7 +572,11 @@ class Databases:
|
|||||||
query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper()))
|
query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper()))
|
||||||
else:
|
else:
|
||||||
query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name))
|
query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name))
|
||||||
|
|
||||||
comment = unArrayizeValue(inject.getValue(query, blind=False, time=False))
|
comment = unArrayizeValue(inject.getValue(query, blind=False, time=False))
|
||||||
|
if not isNoneValue(comment):
|
||||||
|
infoMsg = "retrieved comment '%s' for column '%s'" % (comment, name)
|
||||||
|
logger.info(infoMsg)
|
||||||
else:
|
else:
|
||||||
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
|
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
|
||||||
warnMsg += "possible to get column comments"
|
warnMsg += "possible to get column comments"
|
||||||
@@ -702,7 +706,11 @@ class Databases:
|
|||||||
query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper()))
|
query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper()))
|
||||||
else:
|
else:
|
||||||
query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column))
|
query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column))
|
||||||
|
|
||||||
comment = unArrayizeValue(inject.getValue(query, union=False, error=False))
|
comment = unArrayizeValue(inject.getValue(query, union=False, error=False))
|
||||||
|
if not isNoneValue(comment):
|
||||||
|
infoMsg = "retrieved comment '%s' for column '%s'" % (comment, column)
|
||||||
|
logger.info(infoMsg)
|
||||||
else:
|
else:
|
||||||
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
|
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
|
||||||
warnMsg += "possible to get column comments"
|
warnMsg += "possible to get column comments"
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ from lib.core.common import isListLike
|
|||||||
from lib.core.common import isNoneValue
|
from lib.core.common import isNoneValue
|
||||||
from lib.core.common import isNumPosStrValue
|
from lib.core.common import isNumPosStrValue
|
||||||
from lib.core.common import isTechniqueAvailable
|
from lib.core.common import isTechniqueAvailable
|
||||||
from lib.core.common import popValue
|
|
||||||
from lib.core.common import prioritySortColumns
|
from lib.core.common import prioritySortColumns
|
||||||
from lib.core.common import pushValue
|
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.common import safeSQLIdentificatorNaming
|
from lib.core.common import safeSQLIdentificatorNaming
|
||||||
from lib.core.common import unArrayizeValue
|
from lib.core.common import unArrayizeValue
|
||||||
@@ -214,8 +212,7 @@ class Entries:
|
|||||||
else:
|
else:
|
||||||
colEntry = unArrayizeValue(entry[index]) if index < len(entry) else u''
|
colEntry = unArrayizeValue(entry[index]) if index < len(entry) else u''
|
||||||
|
|
||||||
_ = len(DUMP_REPLACEMENTS.get(getUnicode(colEntry), getUnicode(colEntry)))
|
maxLen = max(len(column), len(DUMP_REPLACEMENTS.get(getUnicode(colEntry), getUnicode(colEntry))))
|
||||||
maxLen = max(len(column), _)
|
|
||||||
|
|
||||||
if maxLen > kb.data.dumpedTable[column]["length"]:
|
if maxLen > kb.data.dumpedTable[column]["length"]:
|
||||||
kb.data.dumpedTable[column]["length"] = maxLen
|
kb.data.dumpedTable[column]["length"] = maxLen
|
||||||
@@ -294,8 +291,11 @@ class Entries:
|
|||||||
indexRange = getLimitRange(count, plusOne=plusOne)
|
indexRange = getLimitRange(count, plusOne=plusOne)
|
||||||
|
|
||||||
if len(colList) < len(indexRange) > CHECK_ZERO_COLUMNS_THRESHOLD:
|
if len(colList) < len(indexRange) > CHECK_ZERO_COLUMNS_THRESHOLD:
|
||||||
|
debugMsg = "checking for empty columns"
|
||||||
|
logger.debug(infoMsg)
|
||||||
|
|
||||||
for column in colList:
|
for column in colList:
|
||||||
if inject.getValue("SELECT COUNT(%s) FROM %s" % (column, kb.dumpTable), union=False, error=False) == '0':
|
if not inject.checkBooleanExpression("(SELECT COUNT(%s) FROM %s)>0" % (column, kb.dumpTable)):
|
||||||
emptyColumns.append(column)
|
emptyColumns.append(column)
|
||||||
debugMsg = "column '%s' of table '%s' will not be " % (column, kb.dumpTable)
|
debugMsg = "column '%s' of table '%s' will not be " % (column, kb.dumpTable)
|
||||||
debugMsg += "dumped as it appears to be empty"
|
debugMsg += "dumped as it appears to be empty"
|
||||||
@@ -329,8 +329,7 @@ class Entries:
|
|||||||
value = NULL if column in emptyColumns else inject.getValue(query, union=False, error=False, dump=True)
|
value = NULL if column in emptyColumns else inject.getValue(query, union=False, error=False, dump=True)
|
||||||
value = '' if value is None else value
|
value = '' if value is None else value
|
||||||
|
|
||||||
_ = DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value))
|
lengths[column] = max(lengths[column], len(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value))))
|
||||||
lengths[column] = max(lengths[column], len(_))
|
|
||||||
entries[column].append(value)
|
entries[column].append(value)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from lib.core.enums import CHARSET_TYPE
|
|||||||
from lib.core.enums import EXPECTED
|
from lib.core.enums import EXPECTED
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
from lib.core.exception import SqlmapUndefinedMethod
|
from lib.core.exception import SqlmapUndefinedMethod
|
||||||
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
|
|
||||||
class Filesystem:
|
class Filesystem:
|
||||||
@@ -69,7 +70,7 @@ class Filesystem:
|
|||||||
|
|
||||||
if isNumPosStrValue(remoteFileSize):
|
if isNumPosStrValue(remoteFileSize):
|
||||||
remoteFileSize = long(remoteFileSize)
|
remoteFileSize = long(remoteFileSize)
|
||||||
localFile = getUnicode(localFile, encoding=sys.getfilesystemencoding())
|
localFile = getUnicode(localFile, encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
|
||||||
sameFile = False
|
sameFile = False
|
||||||
|
|
||||||
if localFileSize == remoteFileSize:
|
if localFileSize == remoteFileSize:
|
||||||
@@ -87,7 +88,7 @@ class Filesystem:
|
|||||||
else:
|
else:
|
||||||
sameFile = False
|
sameFile = False
|
||||||
warnMsg = "it looks like the file has not been written (usually "
|
warnMsg = "it looks like the file has not been written (usually "
|
||||||
warnMsg += "occurs if the DBMS process' user has no write "
|
warnMsg += "occurs if the DBMS process user has no write "
|
||||||
warnMsg += "privileges in the destination path)"
|
warnMsg += "privileges in the destination path)"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ EXEC master..sp_configure 'show advanced options',1;
|
|||||||
RECONFIGURE WITH OVERRIDE;
|
RECONFIGURE WITH OVERRIDE;
|
||||||
EXEC master..sp_configure 'xp_cmdshell',%ENABLE%;
|
EXEC master..sp_configure 'xp_cmdshell',%ENABLE%;
|
||||||
RECONFIGURE WITH OVERRIDE;
|
RECONFIGURE WITH OVERRIDE;
|
||||||
EXEC sp_configure 'show advanced options',0;
|
EXEC master..sp_configure 'show advanced options',0;
|
||||||
RECONFIGURE WITH OVERRIDE
|
RECONFIGURE WITH OVERRIDE
|
||||||
|
|||||||
+13
-7
@@ -482,6 +482,9 @@ col =
|
|||||||
# Back-end database management system database table column(s) to not enumerate.
|
# Back-end database management system database table column(s) to not enumerate.
|
||||||
excludeCol =
|
excludeCol =
|
||||||
|
|
||||||
|
# Pivot column name.
|
||||||
|
pivotColumn =
|
||||||
|
|
||||||
# Use WHERE condition while table dumping (e.g. "id=1").
|
# Use WHERE condition while table dumping (e.g. "id=1").
|
||||||
dumpWhere =
|
dumpWhere =
|
||||||
|
|
||||||
@@ -650,6 +653,9 @@ trafficFile =
|
|||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
batch = False
|
batch = False
|
||||||
|
|
||||||
|
# Result fields having binary values (e.g. "digest").
|
||||||
|
binaryFields =
|
||||||
|
|
||||||
# Force character encoding used for data retrieval.
|
# Force character encoding used for data retrieval.
|
||||||
charset =
|
charset =
|
||||||
|
|
||||||
@@ -697,9 +703,6 @@ outputDir =
|
|||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
parseErrors = False
|
parseErrors = False
|
||||||
|
|
||||||
# Pivot column name.
|
|
||||||
pivotColumn =
|
|
||||||
|
|
||||||
# Regular expression for filtering targets from provided Burp.
|
# Regular expression for filtering targets from provided Burp.
|
||||||
# or WebScarab proxy log.
|
# or WebScarab proxy log.
|
||||||
# Example: (google|yahoo)
|
# Example: (google|yahoo)
|
||||||
@@ -753,10 +756,6 @@ googlePage = 1
|
|||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
identifyWaf = False
|
identifyWaf = False
|
||||||
|
|
||||||
# Skip heuristic detection of WAF/IPS/IDS protection.
|
|
||||||
# Valid: True or False
|
|
||||||
skipWaf = False
|
|
||||||
|
|
||||||
# Imitate smartphone through HTTP User-Agent header.
|
# Imitate smartphone through HTTP User-Agent header.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
mobile = False
|
mobile = False
|
||||||
@@ -769,10 +768,17 @@ offline = False
|
|||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
pageRank = False
|
pageRank = False
|
||||||
|
|
||||||
|
# Skip heuristic detection of WAF/IPS/IDS protection.
|
||||||
|
# Valid: True or False
|
||||||
|
skipWaf = False
|
||||||
|
|
||||||
# Conduct thorough tests only if positive heuristic(s).
|
# Conduct thorough tests only if positive heuristic(s).
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
smart = False
|
smart = False
|
||||||
|
|
||||||
|
# Local directory for storing temporary files.
|
||||||
|
tmpDir =
|
||||||
|
|
||||||
# Simple wizard interface for beginner users.
|
# Simple wizard interface for beginner users.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
wizard = False
|
wizard = False
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ sys.dont_write_bytecode = True
|
|||||||
from lib.utils import versioncheck # this has to be the first non-standard import
|
from lib.utils import versioncheck # this has to be the first non-standard import
|
||||||
|
|
||||||
import bdb
|
import bdb
|
||||||
|
import distutils
|
||||||
|
import glob
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@@ -19,6 +21,7 @@ import re
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import thread
|
import thread
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import warnings
|
import warnings
|
||||||
@@ -26,34 +29,47 @@ import warnings
|
|||||||
warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning)
|
warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning)
|
||||||
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
|
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
|
||||||
|
|
||||||
from lib.controller.controller import start
|
|
||||||
from lib.core.common import banner
|
|
||||||
from lib.core.common import createGithubIssue
|
|
||||||
from lib.core.common import dataToStdout
|
|
||||||
from lib.core.common import getSafeExString
|
|
||||||
from lib.core.common import getUnicode
|
|
||||||
from lib.core.common import maskSensitiveData
|
|
||||||
from lib.core.common import setPaths
|
|
||||||
from lib.core.common import weAreFrozen
|
|
||||||
from lib.core.data import cmdLineOptions
|
|
||||||
from lib.core.data import conf
|
|
||||||
from lib.core.data import kb
|
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import paths
|
|
||||||
from lib.core.common import unhandledExceptionMessage
|
try:
|
||||||
from lib.core.exception import SqlmapBaseException
|
from lib.controller.controller import start
|
||||||
from lib.core.exception import SqlmapShellQuitException
|
from lib.core.common import banner
|
||||||
from lib.core.exception import SqlmapSilentQuitException
|
from lib.core.common import createGithubIssue
|
||||||
from lib.core.exception import SqlmapUserQuitException
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.option import initOptions
|
from lib.core.common import getSafeExString
|
||||||
from lib.core.option import init
|
from lib.core.common import getUnicode
|
||||||
from lib.core.profiling import profile
|
from lib.core.common import maskSensitiveData
|
||||||
from lib.core.settings import LEGAL_DISCLAIMER
|
from lib.core.common import setPaths
|
||||||
from lib.core.testing import smokeTest
|
from lib.core.common import weAreFrozen
|
||||||
from lib.core.testing import liveTest
|
from lib.core.data import cmdLineOptions
|
||||||
from lib.parse.cmdline import cmdLineParser
|
from lib.core.data import conf
|
||||||
from lib.utils.api import setRestAPILog
|
from lib.core.data import kb
|
||||||
from lib.utils.api import StdDbOut
|
from lib.core.data import paths
|
||||||
|
from lib.core.common import unhandledExceptionMessage
|
||||||
|
from lib.core.common import MKSTEMP_PREFIX
|
||||||
|
from lib.core.exception import SqlmapBaseException
|
||||||
|
from lib.core.exception import SqlmapShellQuitException
|
||||||
|
from lib.core.exception import SqlmapSilentQuitException
|
||||||
|
from lib.core.exception import SqlmapUserQuitException
|
||||||
|
from lib.core.option import initOptions
|
||||||
|
from lib.core.option import init
|
||||||
|
from lib.core.profiling import profile
|
||||||
|
from lib.core.settings import GIT_PAGE
|
||||||
|
from lib.core.settings import IS_WIN
|
||||||
|
from lib.core.settings import LEGAL_DISCLAIMER
|
||||||
|
from lib.core.settings import THREAD_FINALIZATION_TIMEOUT
|
||||||
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
|
from lib.core.settings import VERSION
|
||||||
|
from lib.core.testing import smokeTest
|
||||||
|
from lib.core.testing import liveTest
|
||||||
|
from lib.parse.cmdline import cmdLineParser
|
||||||
|
from lib.utils.api import setRestAPILog
|
||||||
|
from lib.utils.api import StdDbOut
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
errMsg = "user aborted"
|
||||||
|
logger.error(errMsg)
|
||||||
|
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
def modulePath():
|
def modulePath():
|
||||||
"""
|
"""
|
||||||
@@ -66,7 +82,26 @@ def modulePath():
|
|||||||
except NameError:
|
except NameError:
|
||||||
_ = inspect.getsourcefile(modulePath)
|
_ = inspect.getsourcefile(modulePath)
|
||||||
|
|
||||||
return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding())
|
return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
|
||||||
|
|
||||||
|
def checkEnvironment():
|
||||||
|
paths.SQLMAP_ROOT_PATH = modulePath()
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.path.isdir(paths.SQLMAP_ROOT_PATH)
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
errMsg = "your system does not properly handle non-ASCII paths. "
|
||||||
|
errMsg += "Please move the sqlmap's directory to the other location"
|
||||||
|
logger.critical(errMsg)
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
if distutils.version.LooseVersion(VERSION) < distutils.version.LooseVersion("1.0"):
|
||||||
|
errMsg = "your runtime environment (e.g. PYTHONPATH) is "
|
||||||
|
errMsg += "broken. Please make sure that you are not running "
|
||||||
|
errMsg += "newer versions of sqlmap with runtime scripts for older "
|
||||||
|
errMsg += "versions"
|
||||||
|
logger.critical(errMsg)
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
@@ -74,17 +109,10 @@ def main():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
paths.SQLMAP_ROOT_PATH = modulePath()
|
checkEnvironment()
|
||||||
|
|
||||||
try:
|
|
||||||
os.path.isdir(paths.SQLMAP_ROOT_PATH)
|
|
||||||
except UnicodeEncodeError:
|
|
||||||
errMsg = "your system does not properly handle non-ASCII paths. "
|
|
||||||
errMsg += "Please move the sqlmap's directory to the other location"
|
|
||||||
logger.error(errMsg)
|
|
||||||
raise SystemExit
|
|
||||||
|
|
||||||
setPaths()
|
setPaths()
|
||||||
|
banner()
|
||||||
|
|
||||||
# Store original command line options for possible later restoration
|
# Store original command line options for possible later restoration
|
||||||
cmdLineOptions.update(cmdLineParser().__dict__)
|
cmdLineOptions.update(cmdLineParser().__dict__)
|
||||||
@@ -97,8 +125,6 @@ def main():
|
|||||||
sys.stderr = StdDbOut(conf.taskid, messagetype="stderr")
|
sys.stderr = StdDbOut(conf.taskid, messagetype="stderr")
|
||||||
setRestAPILog()
|
setRestAPILog()
|
||||||
|
|
||||||
banner()
|
|
||||||
|
|
||||||
conf.showTime = True
|
conf.showTime = True
|
||||||
dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True)
|
dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True)
|
||||||
dataToStdout("[*] starting at %s\n\n" % time.strftime("%X"), forceOutput=True)
|
dataToStdout("[*] starting at %s\n\n" % time.strftime("%X"), forceOutput=True)
|
||||||
@@ -175,11 +201,31 @@ def main():
|
|||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
|
elif all(_ in excMsg for _ in ("No such file", "_'")):
|
||||||
|
errMsg = "corrupted installation detected ('%s'). " % excMsg.strip().split('\n')[-1]
|
||||||
|
errMsg += "You should retrieve the latest development version from official GitHub "
|
||||||
|
errMsg += "repository at '%s'" % GIT_PAGE
|
||||||
|
logger.error(errMsg)
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
elif "Read-only file system" in excMsg:
|
||||||
|
errMsg = "output device is mounted as read-only"
|
||||||
|
logger.error(errMsg)
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
elif "_mkstemp_inner" in excMsg:
|
elif "_mkstemp_inner" in excMsg:
|
||||||
errMsg = "there has been a problem while accessing temporary files"
|
errMsg = "there has been a problem while accessing temporary files"
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
|
elif "can't start new thread" in excMsg:
|
||||||
|
errMsg = "there has been a problem while creating new thread instance. "
|
||||||
|
errMsg += "Please make sure that you are not running too many processes"
|
||||||
|
if not IS_WIN:
|
||||||
|
errMsg += " (or increase the 'ulimit -u' value)"
|
||||||
|
logger.error(errMsg)
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
elif all(_ in excMsg for _ in ("pymysql", "configparser")):
|
elif all(_ in excMsg for _ in ("pymysql", "configparser")):
|
||||||
errMsg = "wrong initialization of pymsql detected (using Python3 dependencies)"
|
errMsg = "wrong initialization of pymsql detected (using Python3 dependencies)"
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
@@ -218,13 +264,21 @@ def main():
|
|||||||
|
|
||||||
finally:
|
finally:
|
||||||
kb.threadContinue = False
|
kb.threadContinue = False
|
||||||
kb.threadException = True
|
|
||||||
|
|
||||||
if conf.get("showTime"):
|
if conf.get("showTime"):
|
||||||
dataToStdout("\n[*] shutting down at %s\n\n" % time.strftime("%X"), forceOutput=True)
|
dataToStdout("\n[*] shutting down at %s\n\n" % time.strftime("%X"), forceOutput=True)
|
||||||
|
|
||||||
|
kb.threadException = True
|
||||||
|
|
||||||
if kb.get("tempDir"):
|
if kb.get("tempDir"):
|
||||||
shutil.rmtree(kb.tempDir, ignore_errors=True)
|
for prefix in (MKSTEMP_PREFIX.IPC, MKSTEMP_PREFIX.TESTING, MKSTEMP_PREFIX.COOKIE_JAR, MKSTEMP_PREFIX.BIG_ARRAY):
|
||||||
|
for filepath in glob.glob(os.path.join(kb.tempDir, "%s*" % prefix)):
|
||||||
|
try:
|
||||||
|
os.remove(filepath)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
if not filter(None, (filepath for filepath in glob.glob(os.path.join(kb.tempDir, '*')) if not any(filepath.endswith(_) for _ in ('.lock', '.exe', '_')))):
|
||||||
|
shutil.rmtree(kb.tempDir, ignore_errors=True)
|
||||||
|
|
||||||
if conf.get("hashDB"):
|
if conf.get("hashDB"):
|
||||||
try:
|
try:
|
||||||
@@ -247,8 +301,16 @@ def main():
|
|||||||
if conf.get("dumper"):
|
if conf.get("dumper"):
|
||||||
conf.dumper.flush()
|
conf.dumper.flush()
|
||||||
|
|
||||||
|
# short delay for thread finalization
|
||||||
|
try:
|
||||||
|
_ = time.time()
|
||||||
|
while threading.activeCount() > 1 and (time.time() - _) > THREAD_FINALIZATION_TIMEOUT:
|
||||||
|
time.sleep(0.01)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
# Reference: http://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program
|
# Reference: http://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program
|
||||||
if conf.get("threads", 0) > 1 or conf.get("dnsServer"):
|
if threading.activeCount() > 1:
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -5,10 +5,8 @@ Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from lib.core.common import singleTimeWarnMessage
|
|
||||||
from lib.core.enums import PRIORITY
|
from lib.core.enums import PRIORITY
|
||||||
|
|
||||||
__priority__ = PRIORITY.HIGH
|
__priority__ = PRIORITY.HIGH
|
||||||
|
|||||||
@@ -5,10 +5,7 @@ Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import base64
|
|
||||||
|
|
||||||
from lib.core.enums import PRIORITY
|
from lib.core.enums import PRIORITY
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
|
||||||
|
|
||||||
__priority__ = PRIORITY.LOWEST
|
__priority__ = PRIORITY.LOWEST
|
||||||
|
|
||||||
|
|||||||
Vendored
+10
-3
@@ -21,13 +21,15 @@ def reset_all():
|
|||||||
|
|
||||||
|
|
||||||
def init(autoreset=False, convert=None, strip=None, wrap=True):
|
def init(autoreset=False, convert=None, strip=None, wrap=True):
|
||||||
|
global wrapped_stdout, wrapped_stderr
|
||||||
|
global orig_stdout, orig_stderr
|
||||||
|
|
||||||
|
if orig_stdout is not None:
|
||||||
|
return
|
||||||
|
|
||||||
if not wrap and any([autoreset, convert, strip]):
|
if not wrap and any([autoreset, convert, strip]):
|
||||||
raise ValueError('wrap=False conflicts with any other arg=True')
|
raise ValueError('wrap=False conflicts with any other arg=True')
|
||||||
|
|
||||||
global wrapped_stdout, wrapped_stderr
|
|
||||||
global orig_stdout, orig_stderr
|
|
||||||
|
|
||||||
orig_stdout = sys.stdout
|
orig_stdout = sys.stdout
|
||||||
orig_stderr = sys.stderr
|
orig_stderr = sys.stderr
|
||||||
|
|
||||||
@@ -49,10 +51,15 @@ def init(autoreset=False, convert=None, strip=None, wrap=True):
|
|||||||
|
|
||||||
|
|
||||||
def deinit():
|
def deinit():
|
||||||
|
global orig_stdout
|
||||||
|
global orig_stderr
|
||||||
|
|
||||||
if orig_stdout is not None:
|
if orig_stdout is not None:
|
||||||
sys.stdout = orig_stdout
|
sys.stdout = orig_stdout
|
||||||
|
orig_stdout = None
|
||||||
if orig_stderr is not None:
|
if orig_stderr is not None:
|
||||||
sys.stderr = orig_stderr
|
sys.stderr = orig_stderr
|
||||||
|
orig_stderr = None
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
|
|||||||
Vendored
+348
-175
@@ -1,30 +1,40 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# 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.
|
||||||
#
|
#
|
||||||
# Copyright 2002-2003 Michael D. Stenner
|
# This library is distributed in the hope that it will be useful,
|
||||||
#
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# This program is free software: you can redistribute it and/or modify it
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
# under the terms of the GNU Lesser General Public License as published
|
# Lesser General Public License for more details.
|
||||||
# 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 Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
#
|
||||||
|
# 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.,
|
||||||
|
# 59 Temple Place, Suite 330,
|
||||||
|
# Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
# This file was part of urlgrabber, a high-level cross-protocol url-grabber
|
||||||
|
# Copyright 2002-2004 Michael D. Stenner, Ryan Tomayko
|
||||||
|
# Copyright 2015 Sergio Fernández
|
||||||
|
|
||||||
"""An HTTP handler for urllib2 that supports HTTP 1.1 and keepalive.
|
"""An HTTP handler for urllib2 that supports HTTP 1.1 and keepalive.
|
||||||
|
|
||||||
import urllib2
|
>>> import urllib2
|
||||||
from keepalive import HTTPHandler
|
>>> from keepalive import HTTPHandler
|
||||||
keepalive_handler = HTTPHandler()
|
>>> keepalive_handler = HTTPHandler()
|
||||||
opener = urllib2.build_opener(keepalive_handler)
|
>>> opener = urllib2.build_opener(keepalive_handler)
|
||||||
urllib2.install_opener(opener)
|
>>> urllib2.install_opener(opener)
|
||||||
|
>>>
|
||||||
|
>>> fo = urllib2.urlopen('http://www.python.org')
|
||||||
|
|
||||||
fo = urllib2.urlopen('http://www.python.org')
|
If a connection to a given host is requested, and all of the existing
|
||||||
|
connections are still in use, another connection will be opened. If
|
||||||
|
the handler tries to use an existing connection but it fails in some
|
||||||
|
way, it will be closed and removed from the pool.
|
||||||
|
|
||||||
To remove the handler, simply re-run build_opener with no arguments, and
|
To remove the handler, simply re-run build_opener with no arguments, and
|
||||||
install that opener.
|
install that opener.
|
||||||
@@ -37,9 +47,13 @@ use the handler methods:
|
|||||||
close_all()
|
close_all()
|
||||||
open_connections()
|
open_connections()
|
||||||
|
|
||||||
Example:
|
NOTE: using the close_connection and close_all methods of the handler
|
||||||
|
should be done with care when using multiple threads.
|
||||||
|
* there is nothing that prevents another thread from creating new
|
||||||
|
connections immediately after connections are closed
|
||||||
|
* no checks are done to prevent in-use connections from being closed
|
||||||
|
|
||||||
keepalive_handler.close_all()
|
>>> keepalive_handler.close_all()
|
||||||
|
|
||||||
EXTRA ATTRIBUTES AND METHODS
|
EXTRA ATTRIBUTES AND METHODS
|
||||||
|
|
||||||
@@ -55,162 +69,307 @@ EXTRA ATTRIBUTES AND METHODS
|
|||||||
If you want the best of both worlds, use this inside an
|
If you want the best of both worlds, use this inside an
|
||||||
AttributeError-catching try:
|
AttributeError-catching try:
|
||||||
|
|
||||||
try: status = fo.status
|
>>> try: status = fo.status
|
||||||
except AttributeError: status = None
|
>>> except AttributeError: status = None
|
||||||
|
|
||||||
Unfortunately, these are ONLY there if status == 200, so it's not
|
Unfortunately, these are ONLY there if status == 200, so it's not
|
||||||
easy to distinguish between non-200 responses. The reason is that
|
easy to distinguish between non-200 responses. The reason is that
|
||||||
urllib2 tries to do clever things with error codes 301, 302, 401,
|
urllib2 tries to do clever things with error codes 301, 302, 401,
|
||||||
and 407, and it wraps the object upon return.
|
and 407, and it wraps the object upon return.
|
||||||
|
|
||||||
You can optionally set the module-level global HANDLE_ERRORS to 0,
|
For python versions earlier than 2.4, you can avoid this fancy error
|
||||||
in which case the handler will always return the object directly.
|
handling by setting the module-level global HANDLE_ERRORS to zero.
|
||||||
If you like the fancy handling of errors, don't do this. If you
|
You see, prior to 2.4, it's the HTTP Handler's job to determine what
|
||||||
prefer to see your error codes, then do.
|
to handle specially, and what to just pass up. HANDLE_ERRORS == 0
|
||||||
|
means "pass everything up". In python 2.4, however, this job no
|
||||||
|
longer belongs to the HTTP Handler and is now done by a NEW handler,
|
||||||
|
HTTPErrorProcessor. Here's the bottom line:
|
||||||
|
|
||||||
|
python version < 2.4
|
||||||
|
HANDLE_ERRORS == 1 (default) pass up 200, treat the rest as
|
||||||
|
errors
|
||||||
|
HANDLE_ERRORS == 0 pass everything up, error processing is
|
||||||
|
left to the calling code
|
||||||
|
python version >= 2.4
|
||||||
|
HANDLE_ERRORS == 1 pass up 200, treat the rest as errors
|
||||||
|
HANDLE_ERRORS == 0 (default) pass everything up, let the
|
||||||
|
other handlers (specifically,
|
||||||
|
HTTPErrorProcessor) decide what to do
|
||||||
|
|
||||||
|
In practice, setting the variable either way makes little difference
|
||||||
|
in python 2.4, so for the most consistent behavior across versions,
|
||||||
|
you probably just want to use the defaults, which will give you
|
||||||
|
exceptions on errors.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from httplib import _CS_REQ_STARTED, _CS_REQ_SENT, _CS_IDLE, CannotSendHeader
|
|
||||||
|
|
||||||
from lib.core.convert import unicodeencode
|
# $Id: keepalive.py,v 1.17 2006/12/08 00:14:16 mstenner Exp $
|
||||||
from lib.core.data import kb
|
|
||||||
|
|
||||||
import threading
|
|
||||||
import urllib2
|
import urllib2
|
||||||
import httplib
|
import httplib
|
||||||
import socket
|
import socket
|
||||||
|
import thread
|
||||||
|
|
||||||
VERSION = (0, 1)
|
DEBUG = None
|
||||||
#STRING_VERSION = '.'.join(map(str, VERSION))
|
|
||||||
DEBUG = 0
|
|
||||||
HANDLE_ERRORS = 1
|
|
||||||
|
|
||||||
class HTTPHandler(urllib2.HTTPHandler):
|
import sys
|
||||||
|
if sys.version_info < (2, 4): HANDLE_ERRORS = 1
|
||||||
|
else: HANDLE_ERRORS = 0
|
||||||
|
|
||||||
|
class ConnectionManager:
|
||||||
|
"""
|
||||||
|
The connection manager must be able to:
|
||||||
|
* keep track of all existing
|
||||||
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._connections = {}
|
self._lock = thread.allocate_lock()
|
||||||
|
self._hostmap = {} # map hosts to a list of connections
|
||||||
|
self._connmap = {} # map connections to host
|
||||||
|
self._readymap = {} # map connection to ready state
|
||||||
|
|
||||||
|
def add(self, host, connection, ready):
|
||||||
|
self._lock.acquire()
|
||||||
|
try:
|
||||||
|
if not self._hostmap.has_key(host): self._hostmap[host] = []
|
||||||
|
self._hostmap[host].append(connection)
|
||||||
|
self._connmap[connection] = host
|
||||||
|
self._readymap[connection] = ready
|
||||||
|
finally:
|
||||||
|
self._lock.release()
|
||||||
|
|
||||||
|
def remove(self, connection):
|
||||||
|
self._lock.acquire()
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
host = self._connmap[connection]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
del self._connmap[connection]
|
||||||
|
del self._readymap[connection]
|
||||||
|
self._hostmap[host].remove(connection)
|
||||||
|
if not self._hostmap[host]: del self._hostmap[host]
|
||||||
|
finally:
|
||||||
|
self._lock.release()
|
||||||
|
|
||||||
|
def set_ready(self, connection, ready):
|
||||||
|
try: self._readymap[connection] = ready
|
||||||
|
except KeyError: pass
|
||||||
|
|
||||||
|
def get_ready_conn(self, host):
|
||||||
|
conn = None
|
||||||
|
self._lock.acquire()
|
||||||
|
try:
|
||||||
|
if self._hostmap.has_key(host):
|
||||||
|
for c in self._hostmap[host]:
|
||||||
|
if self._readymap[c]:
|
||||||
|
self._readymap[c] = 0
|
||||||
|
conn = c
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
self._lock.release()
|
||||||
|
return conn
|
||||||
|
|
||||||
|
def get_all(self, host=None):
|
||||||
|
if host:
|
||||||
|
return list(self._hostmap.get(host, []))
|
||||||
|
else:
|
||||||
|
return dict(self._hostmap)
|
||||||
|
|
||||||
|
class KeepAliveHandler:
|
||||||
|
def __init__(self):
|
||||||
|
self._cm = ConnectionManager()
|
||||||
|
|
||||||
|
#### Connection Management
|
||||||
|
def open_connections(self):
|
||||||
|
"""return a list of connected hosts and the number of connections
|
||||||
|
to each. [('foo.com:80', 2), ('bar.org', 1)]"""
|
||||||
|
return [(host, len(li)) for (host, li) in self._cm.get_all().items()]
|
||||||
|
|
||||||
def close_connection(self, host):
|
def close_connection(self, host):
|
||||||
"""close connection to <host>
|
"""close connection(s) to <host>
|
||||||
host is the host:port spec, as in 'www.cnn.com:8080' as passed in.
|
host is the host:port spec, as in 'www.cnn.com:8080' as passed in.
|
||||||
no error occurs if there is no connection to that host."""
|
no error occurs if there is no connection to that host."""
|
||||||
self._remove_connection(host, close=1)
|
for h in self._cm.get_all(host):
|
||||||
|
self._cm.remove(h)
|
||||||
def open_connections(self):
|
h.close()
|
||||||
"""return a list of connected hosts"""
|
|
||||||
retVal = []
|
|
||||||
currentThread = threading.currentThread()
|
|
||||||
for name, host in self._connections.keys():
|
|
||||||
if name == currentThread.getName():
|
|
||||||
retVal.append(host)
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
def close_all(self):
|
def close_all(self):
|
||||||
"""close all open connections"""
|
"""close all open connections"""
|
||||||
for _, conn in self._connections.items():
|
for host, conns in self._cm.get_all().items():
|
||||||
conn.close()
|
for h in conns:
|
||||||
self._connections = {}
|
self._cm.remove(h)
|
||||||
|
h.close()
|
||||||
|
|
||||||
def _remove_connection(self, host, close=0):
|
def _request_closed(self, request, host, connection):
|
||||||
key = self._get_connection_key(host)
|
"""tells us that this request is now closed and the the
|
||||||
if self._connections.has_key(key):
|
connection is ready for another request"""
|
||||||
if close: self._connections[key].close()
|
self._cm.set_ready(connection, 1)
|
||||||
del self._connections[key]
|
|
||||||
|
|
||||||
def _get_connection_key(self, host):
|
def _remove_connection(self, host, connection, close=0):
|
||||||
return (threading.currentThread().getName(), host)
|
if close: connection.close()
|
||||||
|
self._cm.remove(connection)
|
||||||
|
|
||||||
def _start_connection(self, h, req):
|
#### Transaction Execution
|
||||||
h.clearheaders()
|
def do_open(self, req):
|
||||||
try:
|
host = req.host
|
||||||
if req.has_data():
|
|
||||||
data = req.get_data()
|
|
||||||
h.putrequest('POST', req.get_selector())
|
|
||||||
if not req.headers.has_key('Content-type'):
|
|
||||||
req.headers['Content-type'] = 'application/x-www-form-urlencoded'
|
|
||||||
if not req.headers.has_key('Content-length'):
|
|
||||||
req.headers['Content-length'] = '%d' % len(data)
|
|
||||||
else:
|
|
||||||
h.putrequest(req.get_method() or 'GET', req.get_selector())
|
|
||||||
|
|
||||||
if not req.headers.has_key('Connection'):
|
|
||||||
req.headers['Connection'] = 'keep-alive'
|
|
||||||
|
|
||||||
for args in self.parent.addheaders:
|
|
||||||
h.putheader(*args)
|
|
||||||
for k, v in req.headers.items():
|
|
||||||
h.putheader(k, v)
|
|
||||||
h.endheaders()
|
|
||||||
if req.has_data():
|
|
||||||
h.send(data)
|
|
||||||
except socket.error, err:
|
|
||||||
h.close()
|
|
||||||
raise urllib2.URLError(err)
|
|
||||||
|
|
||||||
def do_open(self, http_class, req):
|
|
||||||
h = None
|
|
||||||
host = req.get_host()
|
|
||||||
if not host:
|
if not host:
|
||||||
raise urllib2.URLError('no host given')
|
raise urllib2.URLError('no host given')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
need_new_connection = 1
|
h = self._cm.get_ready_conn(host)
|
||||||
key = self._get_connection_key(host)
|
while h:
|
||||||
h = self._connections.get(key)
|
r = self._reuse_connection(h, req, host)
|
||||||
if not h is None:
|
|
||||||
try:
|
|
||||||
self._start_connection(h, req)
|
|
||||||
except:
|
|
||||||
r = None
|
|
||||||
else:
|
|
||||||
try: r = h.getresponse()
|
|
||||||
except httplib.ResponseNotReady, e: r = None
|
|
||||||
except httplib.BadStatusLine, e: r = None
|
|
||||||
|
|
||||||
if r is None or r.version == 9:
|
# if this response is non-None, then it worked and we're
|
||||||
# httplib falls back to assuming HTTP 0.9 if it gets a
|
# done. Break out, skipping the else block.
|
||||||
# bad header back. This is most likely to happen if
|
if r: break
|
||||||
# the socket has been closed by the server since we
|
|
||||||
# last used the connection.
|
# connection is bad - possibly closed by server
|
||||||
if DEBUG: print "failed to re-use connection to %s" % host
|
# discard it and ask for the next free connection
|
||||||
h.close()
|
h.close()
|
||||||
else:
|
self._cm.remove(h)
|
||||||
if DEBUG: print "re-using connection to %s" % host
|
h = self._cm.get_ready_conn(host)
|
||||||
need_new_connection = 0
|
else:
|
||||||
if need_new_connection:
|
# no (working) free connections were found. Create a new one.
|
||||||
if DEBUG: print "creating new connection to %s" % host
|
h = self._get_connection(host)
|
||||||
h = http_class(host)
|
if DEBUG: DEBUG.info("creating new connection to %s (%d)",
|
||||||
self._connections[key] = h
|
host, id(h))
|
||||||
self._start_connection(h, req)
|
self._cm.add(host, h, 0)
|
||||||
|
self._start_transaction(h, req)
|
||||||
r = h.getresponse()
|
r = h.getresponse()
|
||||||
except socket.error, err:
|
except (socket.error, httplib.HTTPException), err:
|
||||||
if h: h.close()
|
|
||||||
raise urllib2.URLError(err)
|
raise urllib2.URLError(err)
|
||||||
|
|
||||||
|
if DEBUG: DEBUG.info("STATUS: %s, %s", r.status, r.reason)
|
||||||
|
|
||||||
# if not a persistent connection, don't try to reuse it
|
# if not a persistent connection, don't try to reuse it
|
||||||
if r.will_close: self._remove_connection(host)
|
if r.will_close:
|
||||||
|
if DEBUG: DEBUG.info('server will close connection, discarding')
|
||||||
|
self._cm.remove(h)
|
||||||
|
|
||||||
if DEBUG:
|
|
||||||
print "STATUS: %s, %s" % (r.status, r.reason)
|
|
||||||
r._handler = self
|
r._handler = self
|
||||||
r._host = host
|
r._host = host
|
||||||
r._url = req.get_full_url()
|
r._url = req.get_full_url()
|
||||||
|
r._connection = h
|
||||||
|
r.code = r.status
|
||||||
|
r.headers = r.msg
|
||||||
|
r.msg = r.reason
|
||||||
|
|
||||||
#if r.status == 200 or not HANDLE_ERRORS:
|
|
||||||
#return r
|
|
||||||
if r.status == 200 or not HANDLE_ERRORS:
|
if r.status == 200 or not HANDLE_ERRORS:
|
||||||
# [speedplane] Must return an adinfourl object
|
return r
|
||||||
resp = urllib2.addinfourl(r, r.msg, req.get_full_url())
|
|
||||||
resp.code = r.status
|
|
||||||
resp.msg = r.reason
|
|
||||||
return resp;
|
|
||||||
else:
|
else:
|
||||||
r.code = r.status
|
return self.parent.error('http', req, r,
|
||||||
return self.parent.error('http', req, r, r.status, r.reason, r.msg)
|
r.status, r.msg, r.headers)
|
||||||
|
|
||||||
|
def _reuse_connection(self, h, req, host):
|
||||||
|
"""start the transaction with a re-used connection
|
||||||
|
return a response object (r) upon success or None on failure.
|
||||||
|
This DOES not close or remove bad connections in cases where
|
||||||
|
it returns. However, if an unexpected exception occurs, it
|
||||||
|
will close and remove the connection before re-raising.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self._start_transaction(h, req)
|
||||||
|
r = h.getresponse()
|
||||||
|
# note: just because we got something back doesn't mean it
|
||||||
|
# worked. We'll check the version below, too.
|
||||||
|
except (socket.error, httplib.HTTPException):
|
||||||
|
r = None
|
||||||
|
except:
|
||||||
|
# adding this block just in case we've missed
|
||||||
|
# something we will still raise the exception, but
|
||||||
|
# lets try and close the connection and remove it
|
||||||
|
# first. We previously got into a nasty loop
|
||||||
|
# where an exception was uncaught, and so the
|
||||||
|
# connection stayed open. On the next try, the
|
||||||
|
# same exception was raised, etc. The tradeoff is
|
||||||
|
# that it's now possible this call will raise
|
||||||
|
# a DIFFERENT exception
|
||||||
|
if DEBUG: DEBUG.error("unexpected exception - closing " + \
|
||||||
|
"connection to %s (%d)", host, id(h))
|
||||||
|
self._cm.remove(h)
|
||||||
|
h.close()
|
||||||
|
raise
|
||||||
|
|
||||||
|
if r is None or r.version == 9:
|
||||||
|
# httplib falls back to assuming HTTP 0.9 if it gets a
|
||||||
|
# bad header back. This is most likely to happen if
|
||||||
|
# the socket has been closed by the server since we
|
||||||
|
# last used the connection.
|
||||||
|
if DEBUG: DEBUG.info("failed to re-use connection to %s (%d)",
|
||||||
|
host, id(h))
|
||||||
|
r = None
|
||||||
|
else:
|
||||||
|
if DEBUG: DEBUG.info("re-using connection to %s (%d)", host, id(h))
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
def _start_transaction(self, h, req):
|
||||||
|
try:
|
||||||
|
if req.has_data():
|
||||||
|
data = req.data
|
||||||
|
if hasattr(req, 'selector'):
|
||||||
|
h.putrequest(req.get_method() or 'POST', req.selector, skip_host=req.has_header("Host"), skip_accept_encoding=req.has_header("Accept-encoding"))
|
||||||
|
else:
|
||||||
|
h.putrequest(req.get_method() or 'POST', req.get_selector(), skip_host=req.has_header("Host"), skip_accept_encoding=req.has_header("Accept-encoding"))
|
||||||
|
if not req.headers.has_key('Content-type'):
|
||||||
|
h.putheader('Content-type',
|
||||||
|
'application/x-www-form-urlencoded')
|
||||||
|
if not req.headers.has_key('Content-length'):
|
||||||
|
h.putheader('Content-length', '%d' % len(data))
|
||||||
|
else:
|
||||||
|
if hasattr(req, 'selector'):
|
||||||
|
h.putrequest(req.get_method() or 'GET', req.selector, skip_host=req.has_header("Host"), skip_accept_encoding=req.has_header("Accept-encoding"))
|
||||||
|
else:
|
||||||
|
h.putrequest(req.get_method() or 'GET', req.get_selector(), skip_host=req.has_header("Host"), skip_accept_encoding=req.has_header("Accept-encoding"))
|
||||||
|
except (socket.error, httplib.HTTPException), err:
|
||||||
|
raise urllib2.URLError(err)
|
||||||
|
|
||||||
|
if not req.headers.has_key('Connection'):
|
||||||
|
req.headers['Connection'] = 'keep-alive'
|
||||||
|
|
||||||
|
for args in self.parent.addheaders:
|
||||||
|
if not req.headers.has_key(args[0]):
|
||||||
|
h.putheader(*args)
|
||||||
|
for k, v in req.headers.items():
|
||||||
|
h.putheader(k, v)
|
||||||
|
h.endheaders()
|
||||||
|
if req.has_data():
|
||||||
|
h.send(data)
|
||||||
|
|
||||||
|
def _get_connection(self, host):
|
||||||
|
return NotImplementedError
|
||||||
|
|
||||||
|
class HTTPHandler(KeepAliveHandler, urllib2.HTTPHandler):
|
||||||
|
def __init__(self):
|
||||||
|
KeepAliveHandler.__init__(self)
|
||||||
|
|
||||||
def http_open(self, req):
|
def http_open(self, req):
|
||||||
return self.do_open(HTTPConnection, req)
|
return self.do_open(req)
|
||||||
|
|
||||||
|
def _get_connection(self, host):
|
||||||
|
return HTTPConnection(host)
|
||||||
|
|
||||||
|
class HTTPSHandler(KeepAliveHandler, urllib2.HTTPSHandler):
|
||||||
|
def __init__(self, ssl_factory=None):
|
||||||
|
KeepAliveHandler.__init__(self)
|
||||||
|
if not ssl_factory:
|
||||||
|
try:
|
||||||
|
import sslfactory
|
||||||
|
ssl_factory = sslfactory.get_factory()
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
self._ssl_factory = ssl_factory
|
||||||
|
|
||||||
|
def https_open(self, req):
|
||||||
|
return self.do_open(req)
|
||||||
|
|
||||||
|
def _get_connection(self, host):
|
||||||
|
try: return self._ssl_factory.get_https_connection(host)
|
||||||
|
except AttributeError: return HTTPSConnection(host)
|
||||||
|
|
||||||
class HTTPResponse(httplib.HTTPResponse):
|
class HTTPResponse(httplib.HTTPResponse):
|
||||||
|
|
||||||
# we need to subclass HTTPResponse in order to
|
# we need to subclass HTTPResponse in order to
|
||||||
# 1) add readline() and readlines() methods
|
# 1) add readline() and readlines() methods
|
||||||
# 2) add close_connection() methods
|
# 2) add close_connection() methods
|
||||||
@@ -236,21 +395,31 @@ class HTTPResponse(httplib.HTTPResponse):
|
|||||||
else: # 2.2 doesn't
|
else: # 2.2 doesn't
|
||||||
httplib.HTTPResponse.__init__(self, sock, debuglevel)
|
httplib.HTTPResponse.__init__(self, sock, debuglevel)
|
||||||
self.fileno = sock.fileno
|
self.fileno = sock.fileno
|
||||||
|
self.code = None
|
||||||
self._method = method
|
self._method = method
|
||||||
self._rbuf = ''
|
self._rbuf = b""
|
||||||
self._rbufsize = 8096
|
self._rbufsize = 8096
|
||||||
self._handler = None # inserted by the handler later
|
self._handler = None # inserted by the handler later
|
||||||
self._host = None # (same)
|
self._host = None # (same)
|
||||||
self._url = None # (same)
|
self._url = None # (same)
|
||||||
|
self._connection = None # (same)
|
||||||
|
|
||||||
_raw_read = httplib.HTTPResponse.read
|
_raw_read = httplib.HTTPResponse.read
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.fp:
|
||||||
|
self.fp.close()
|
||||||
|
self.fp = None
|
||||||
|
if self._handler:
|
||||||
|
self._handler._request_closed(self, self._host,
|
||||||
|
self._connection)
|
||||||
|
|
||||||
def close_connection(self):
|
def close_connection(self):
|
||||||
|
self._handler._remove_connection(self._host, self._connection, close=1)
|
||||||
self.close()
|
self.close()
|
||||||
self._handler._remove_connection(self._host, close=1)
|
|
||||||
|
|
||||||
def info(self):
|
def info(self):
|
||||||
return self.msg
|
return self.headers
|
||||||
|
|
||||||
def geturl(self):
|
def geturl(self):
|
||||||
return self._url
|
return self._url
|
||||||
@@ -268,11 +437,11 @@ class HTTPResponse(httplib.HTTPResponse):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
s = self._rbuf + self._raw_read(amt)
|
s = self._rbuf + self._raw_read(amt)
|
||||||
self._rbuf = ''
|
self._rbuf = b""
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def readline(self, limit=-1):
|
def readline(self, limit=-1):
|
||||||
data = ""
|
data = b""
|
||||||
i = self._rbuf.find('\n')
|
i = self._rbuf.find('\n')
|
||||||
while i < 0 and not (0 < limit <= len(self._rbuf)):
|
while i < 0 and not (0 < limit <= len(self._rbuf)):
|
||||||
new = self._raw_read(self._rbufsize)
|
new = self._raw_read(self._rbufsize)
|
||||||
@@ -302,43 +471,9 @@ class HTTPResponse(httplib.HTTPResponse):
|
|||||||
class HTTPConnection(httplib.HTTPConnection):
|
class HTTPConnection(httplib.HTTPConnection):
|
||||||
# use the modified response class
|
# use the modified response class
|
||||||
response_class = HTTPResponse
|
response_class = HTTPResponse
|
||||||
_headers = None
|
|
||||||
|
|
||||||
def clearheaders(self):
|
class HTTPSConnection(httplib.HTTPSConnection):
|
||||||
self._headers = {}
|
response_class = HTTPResponse
|
||||||
|
|
||||||
def putheader(self, header, value):
|
|
||||||
"""Send a request header line to the server.
|
|
||||||
|
|
||||||
For example: h.putheader('Accept', 'text/html')
|
|
||||||
"""
|
|
||||||
if self.__state != _CS_REQ_STARTED:
|
|
||||||
raise CannotSendHeader()
|
|
||||||
|
|
||||||
self._headers[header] = value
|
|
||||||
|
|
||||||
def endheaders(self):
|
|
||||||
"""Indicate that the last header line has been sent to the server."""
|
|
||||||
|
|
||||||
if self.__state == _CS_REQ_STARTED:
|
|
||||||
self.__state = _CS_REQ_SENT
|
|
||||||
else:
|
|
||||||
raise CannotSendHeader()
|
|
||||||
|
|
||||||
for header in ('Host', 'Accept-Encoding'):
|
|
||||||
if header in self._headers:
|
|
||||||
str = '%s: %s' % (header, self._headers[header])
|
|
||||||
self._output(str)
|
|
||||||
del self._headers[header]
|
|
||||||
|
|
||||||
for header, value in self._headers.items():
|
|
||||||
str = '%s: %s' % (header, value)
|
|
||||||
self._output(str)
|
|
||||||
|
|
||||||
self._send_output()
|
|
||||||
|
|
||||||
def send(self, str):
|
|
||||||
httplib.HTTPConnection.send(self, unicodeencode(str, kb.pageEncoding))
|
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
##### TEST FUNCTIONS
|
##### TEST FUNCTIONS
|
||||||
@@ -367,7 +502,7 @@ def error_handler(url):
|
|||||||
print " status = %s, reason = %s" % (status, reason)
|
print " status = %s, reason = %s" % (status, reason)
|
||||||
HANDLE_ERRORS = orig
|
HANDLE_ERRORS = orig
|
||||||
hosts = keepalive_handler.open_connections()
|
hosts = keepalive_handler.open_connections()
|
||||||
print "open connections:", ' '.join(hosts)
|
print "open connections:", hosts
|
||||||
keepalive_handler.close_all()
|
keepalive_handler.close_all()
|
||||||
|
|
||||||
def continuity(url):
|
def continuity(url):
|
||||||
@@ -422,9 +557,10 @@ def comp(N, url):
|
|||||||
print ' improvement factor: %.2f' % (t1/t2, )
|
print ' improvement factor: %.2f' % (t1/t2, )
|
||||||
|
|
||||||
def fetch(N, url, delay=0):
|
def fetch(N, url, delay=0):
|
||||||
|
import time
|
||||||
lens = []
|
lens = []
|
||||||
starttime = time.time()
|
starttime = time.time()
|
||||||
for i in xrange(N):
|
for i in range(N):
|
||||||
if delay and i > 0: time.sleep(delay)
|
if delay and i > 0: time.sleep(delay)
|
||||||
fo = urllib2.urlopen(url)
|
fo = urllib2.urlopen(url)
|
||||||
foo = fo.read()
|
foo = fo.read()
|
||||||
@@ -440,6 +576,40 @@ def fetch(N, url, delay=0):
|
|||||||
|
|
||||||
return diff
|
return diff
|
||||||
|
|
||||||
|
def test_timeout(url):
|
||||||
|
global DEBUG
|
||||||
|
dbbackup = DEBUG
|
||||||
|
class FakeLogger:
|
||||||
|
def debug(self, msg, *args): print msg % args
|
||||||
|
info = warning = error = debug
|
||||||
|
DEBUG = FakeLogger()
|
||||||
|
print " fetching the file to establish a connection"
|
||||||
|
fo = urllib2.urlopen(url)
|
||||||
|
data1 = fo.read()
|
||||||
|
fo.close()
|
||||||
|
|
||||||
|
i = 20
|
||||||
|
print " waiting %i seconds for the server to close the connection" % i
|
||||||
|
while i > 0:
|
||||||
|
sys.stdout.write('\r %2i' % i)
|
||||||
|
sys.stdout.flush()
|
||||||
|
time.sleep(1)
|
||||||
|
i -= 1
|
||||||
|
sys.stderr.write('\r')
|
||||||
|
|
||||||
|
print " fetching the file a second time"
|
||||||
|
fo = urllib2.urlopen(url)
|
||||||
|
data2 = fo.read()
|
||||||
|
fo.close()
|
||||||
|
|
||||||
|
if data1 == data2:
|
||||||
|
print ' data are identical'
|
||||||
|
else:
|
||||||
|
print ' ERROR: DATA DIFFER'
|
||||||
|
|
||||||
|
DEBUG = dbbackup
|
||||||
|
|
||||||
|
|
||||||
def test(url, N=10):
|
def test(url, N=10):
|
||||||
print "checking error hander (do this on a non-200)"
|
print "checking error hander (do this on a non-200)"
|
||||||
try: error_handler(url)
|
try: error_handler(url)
|
||||||
@@ -452,6 +622,9 @@ def test(url, N=10):
|
|||||||
print
|
print
|
||||||
print "performing speed comparison"
|
print "performing speed comparison"
|
||||||
comp(N, url)
|
comp(N, url)
|
||||||
|
print
|
||||||
|
print "performing dropped-connection check"
|
||||||
|
test_timeout(url)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import time
|
import time
|
||||||
|
|||||||
+2
-1
@@ -15,8 +15,9 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = re.search(r"wangzhan\.360\.cn", headers.get("X-Powered-By-360wzb", ""), re.I) is not None
|
retval = re.search(r"wangzhan\.360\.cn", headers.get("X-Powered-By-360wzb", ""), re.I) is not None
|
||||||
|
retval |= code == 493 and "/wzws-waf-cgi/" in (page or "")
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -15,8 +15,9 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = re.search(r"MISS", headers.get("X-Powered-By-Anquanbao", ""), re.I) is not None
|
retval = re.search(r"MISS", headers.get("X-Powered-By-Anquanbao", ""), re.I) is not None
|
||||||
|
retval |= code == 405 and "/aqb_cc/error/" in (page or "")
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "Armor Protection (Armor Defense)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
page, _, _ = get_page(get=vector)
|
||||||
|
retval = "This request has been blocked by website protection from Armor" in (page or "")
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
+1
-1
@@ -18,7 +18,7 @@ def detect(get_page):
|
|||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
_, headers, _ = get_page(get=vector)
|
||||||
retval = re.search(r"fhl", headers.get("X-Server", ""), re.I) is not None
|
retval = re.search(r"fhl", headers.get("X-Server", ""), re.I) is not None
|
||||||
retval |= re.search(r"yunjiasu-nginx", headers.get(HTTP_HEADER.SERVER), re.I) is not None
|
retval |= re.search(r"yunjiasu-nginx", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -18,8 +18,10 @@ def detect(get_page):
|
|||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
_, headers, _ = get_page(get=vector)
|
||||||
retval = headers.get("X-Cnection", "").lower() == "close"
|
retval = headers.get("X-Cnection", "").lower() == "close"
|
||||||
retval |= re.search(r"\ATS[a-zA-Z0-9]{3,6}=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
retval |= re.search(r"\ATS[a-zA-Z0-9]{4,}=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
|
retval |= re.search(r"BigIP|BIGipServer", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
retval |= re.search(r"BigIP|BIGipServer", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retval |= re.search(r"BigIP|BIGipServer", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
|
retval |= re.search(r"\AF5\Z", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -16,9 +16,14 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = re.search(r"cloudflare-nginx", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retval = re.search(r"cloudflare-nginx", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
retval |= re.search(r"\A__cfduid=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
|
||||||
|
if code >= 400:
|
||||||
|
retval |= re.search(r"\A__cfduid=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
|
retval |= headers.get("cf-ray") is not None
|
||||||
|
retval |= re.search(r"CloudFlare Ray ID:|var CloudFlare=", page or "") is not None
|
||||||
|
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "CloudFront (Amazon)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
_, headers, _ = get_page(get=vector)
|
||||||
|
|
||||||
|
retval |= re.search(r"cloudfront", headers.get("X-Cache", ""), re.I) is not None
|
||||||
|
retval |= headers.get("X-Amz-Cf-Id") is not None
|
||||||
|
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from lib.core.enums import HTTP_HEADER
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "Comodo Web Application Firewall (Comodo)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
_, headers, _ = get_page(get=vector)
|
||||||
|
retval = re.search(r"Protected by COMODO WAF", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
+1
-1
@@ -18,7 +18,7 @@ def detect(get_page):
|
|||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, headers, code = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = re.search(r"\Asessioncookie=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
retval = re.search(r"\Asessioncookie=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
retval |= code == 200 and re.search(r"\ACondition Intercepted", page, re.I) is not None
|
retval |= code == 200 and re.search(r"\ACondition Intercepted", page or "", re.I) is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -13,9 +13,10 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
page, headers, _ = get_page(get=vector)
|
||||||
retVal = headers.get("X-dotDefender-denied", "") == "1"
|
retval = headers.get("X-dotDefender-denied", "") == "1"
|
||||||
if retVal:
|
retval |= "dotDefender Blocked Your Request" in (page or "")
|
||||||
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|||||||
+4
-4
@@ -13,12 +13,12 @@ from lib.core.settings import WAF_ATTACK_VECTORS
|
|||||||
__product__ = "EdgeCast WAF (Verizon)"
|
__product__ = "EdgeCast WAF (Verizon)"
|
||||||
|
|
||||||
def detect(get_page):
|
def detect(get_page):
|
||||||
retVal = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, code = get_page(get=vector)
|
_, headers, code = get_page(get=vector)
|
||||||
retVal = code == 400 and re.search(r"\AECDF", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retval = code == 400 and re.search(r"\AECDF", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
if retVal:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
return retVal
|
return retval
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ def detect(get_page):
|
|||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, _, _ = get_page(get=vector)
|
page, _, _ = get_page(get=vector)
|
||||||
retval = "Invalid GET Data" in page
|
retval = "Invalid GET Data" in (page or "")
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "Generic (Unknown)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
page, _, code = get_page()
|
||||||
|
if page is None or code >= 400:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
page, _, code = get_page(get=vector)
|
||||||
|
|
||||||
|
if code >= 400 or IDS_WAF_CHECK_PAYLOAD in vector and code is None:
|
||||||
|
retval = True
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
+2
-1
@@ -16,9 +16,10 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
page, headers, _ = get_page(get=vector)
|
||||||
retval = re.search(r"incap_ses|visid_incap", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
retval = re.search(r"incap_ses|visid_incap", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
retval |= re.search(r"Incapsula", headers.get("X-CDN", ""), re.I) is not None
|
retval |= re.search(r"Incapsula", headers.get("X-CDN", ""), re.I) is not None
|
||||||
|
retval |= "Incapsula incident ID" in (page or "")
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -16,10 +16,12 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, headers, _ = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = re.search(r"jiasule-WAF", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retval = re.search(r"jiasule-WAF", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
retval |= re.search(r"__jsluid=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
retval |= re.search(r"__jsluid=", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
retval |= re.search(r"static\.jiasule\.com/static/js/http_error\.js", page, re.I) is not None
|
retval |= re.search(r"jsl_tracking", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
|
retval |= re.search(r"static\.jiasule\.com/static/js/http_error\.js", page or "", re.I) is not None
|
||||||
|
retval |= code == 403 and "notice-jiasule" in (page or "")
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ def detect(get_page):
|
|||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, _, _ = get_page(get=vector)
|
page, _, _ = get_page(get=vector)
|
||||||
retval = re.search(r"url\('/ks-waf-error\.png'\)", page, re.I) is not None
|
retval = re.search(r"url\('/ks-waf-error\.png'\)", page or "", re.I) is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -7,6 +7,7 @@ See the file 'doc/COPYING' for copying permission
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.settings import WAF_ATTACK_VECTORS
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
__product__ = "KONA Security Solutions (Akamai Technologies)"
|
__product__ = "KONA Security Solutions (Akamai Technologies)"
|
||||||
@@ -15,8 +16,9 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, _, code = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = code in (400, 501) and re.search(r"Reference #[0-9A-Fa-f.]+", page, re.I) is not None
|
retval = code in (400, 403, 501) and re.search(r"Reference #[0-9A-Fa-f.]+", page or "", re.I) is not None
|
||||||
|
retval |= re.search(r"AkamaiGHost", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -17,9 +17,9 @@ def detect(get_page):
|
|||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, headers, code = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = code == 501 and re.search(r"Reference #[0-9A-Fa-f.]+", page, re.I) is None
|
retval = code == 501 and re.search(r"Reference #[0-9A-Fa-f.]+", page or "", re.I) is None
|
||||||
retval |= re.search(r"Mod_Security|NOYB", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retval |= re.search(r"Mod_Security|NOYB", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
retval |= "This error was generated by Mod_Security" in page
|
retval |= "This error was generated by Mod_Security" in (page or "")
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from lib.core.enums import HTTP_HEADER
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "NSFOCUS Web Application Firewall (NSFOCUS)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
_, headers, _ = get_page(get=vector)
|
||||||
|
retval = re.search(r"NSFocus", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
+1
-1
@@ -16,7 +16,7 @@ def detect(get_page):
|
|||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, _, _ = get_page(get=vector)
|
page, _, _ = get_page(get=vector)
|
||||||
retval = re.search(r"Access[^<]+has been blocked in accordance with company policy", page, re.I) is not None
|
retval = re.search(r"Access[^<]+has been blocked in accordance with company policy", page or "", re.I) is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ def detect(get_page):
|
|||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, headers, _ = get_page(get=vector)
|
page, headers, _ = get_page(get=vector)
|
||||||
retval = re.search(r"Unauthorized Activity Has Been Detected.+Case Number:", page, re.I | re.S) is not None
|
retval = re.search(r"Unauthorized Activity Has Been Detected.+Case Number:", page or "", re.I | re.S) is not None
|
||||||
retval |= headers.get("X-SL-CompState") is not None
|
retval |= headers.get("X-SL-CompState") is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, _, _ = get_page(get=vector)
|
page, _, code = get_page(get=vector)
|
||||||
retval = "ASP.NET has detected data in the request that is potentially dangerous" in page
|
retval = "ASP.NET has detected data in the request that is potentially dangerous" in (page or "")
|
||||||
retval |= "Request Validation has detected a potentially dangerous client input value" in page
|
retval |= "Request Validation has detected a potentially dangerous client input value" in (page or "")
|
||||||
|
retval |= code == 500 and "HttpRequestValidationException" in page
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+13
-5
@@ -5,13 +5,21 @@ Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
|||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from lib.core.enums import HTTP_HEADER
|
import re
|
||||||
|
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
__product__ = "SecureIIS Web Server Security (BeyondTrust)"
|
__product__ = "SecureIIS Web Server Security (BeyondTrust)"
|
||||||
|
|
||||||
def detect(get_page):
|
def detect(get_page):
|
||||||
_, _, code = get_page()
|
retval = False
|
||||||
retval = code != 404
|
|
||||||
_, _, code = get_page(auxHeaders={HTTP_HEADER.TRANSFER_ENCODING: 'a' * 1025, HTTP_HEADER.ACCEPT_ENCODING: "identity"})
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
retval = retval and code == 404
|
page, _, _ = get_page(get=vector)
|
||||||
|
retval = re.search(r"SecureIIS[^<]+Web Server Protection", page or "") is not None
|
||||||
|
retval |= "http://www.eeye.com/SecureIIS/" in (page or "")
|
||||||
|
retval |= re.search(r"\?subject=[^>]*SecureIIS Error", page or "") is not None
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ def detect(get_page):
|
|||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, _, _ = get_page(get=vector)
|
page, _, _ = get_page(get=vector)
|
||||||
retval = "SENGINX-ROBOT-MITIGATION" in page
|
retval = "SENGINX-ROBOT-MITIGATION" in (page or "")
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "TrueShield Web Application Firewall (SiteLock)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
page, _, _ = get_page(get=vector)
|
||||||
|
retval = "SiteLock Incident ID" in (page or "")
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from lib.core.enums import HTTP_HEADER
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "SonicWALL (Dell)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
page, headers, _ = get_page(get=vector)
|
||||||
|
retval = "This request is blocked by the SonicWALL" in (page or "")
|
||||||
|
retval |= re.search(r"SonicWALL", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "UTM Web Protection (Sophos)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
page, _, _ = get_page(get=vector)
|
||||||
|
retval = "Powered by UTM Web Protection" in (page or "")
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
|
||||||
|
See the file 'doc/COPYING' for copying permission
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from lib.core.enums import HTTP_HEADER
|
||||||
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
|
__product__ = "Stingray Application Firewall (Riverbed / Brocade)"
|
||||||
|
|
||||||
|
def detect(get_page):
|
||||||
|
retval = False
|
||||||
|
|
||||||
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
|
_, headers, code = get_page(get=vector)
|
||||||
|
retval = code in (403, 500) and re.search(r"\AX-Mapping-", headers.get(HTTP_HEADER.SET_COOKIE, ""), re.I) is not None
|
||||||
|
if retval:
|
||||||
|
break
|
||||||
|
|
||||||
|
return retval
|
||||||
+4
-4
@@ -13,12 +13,12 @@ from lib.core.settings import WAF_ATTACK_VECTORS
|
|||||||
__product__ = "Sucuri WebSite Firewall"
|
__product__ = "Sucuri WebSite Firewall"
|
||||||
|
|
||||||
def detect(get_page):
|
def detect(get_page):
|
||||||
retVal = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, code = get_page(get=vector)
|
_, headers, code = get_page(get=vector)
|
||||||
retVal = code == 403 and re.search(r"Sucuri/Cloudproxy", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retval = code == 403 and re.search(r"Sucuri/Cloudproxy", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
if retVal:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
return retVal
|
return retval
|
||||||
|
|||||||
+2
-1
@@ -16,8 +16,9 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = re.search(r"Rejected-By-UrlScan", headers.get(HTTP_HEADER.LOCATION, ""), re.I) is not None
|
retval = re.search(r"Rejected-By-UrlScan", headers.get(HTTP_HEADER.LOCATION, ""), re.I) is not None
|
||||||
|
retval |= code != 200 and re.search(r"/Rejected-By-UrlScan", page or "", re.I) is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -16,9 +16,11 @@ def detect(get_page):
|
|||||||
retval = False
|
retval = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
_, headers, _ = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retval = headers.get("X-Varnish") is not None
|
retval = headers.get("X-Varnish") is not None
|
||||||
retval |= re.search(r"varnish\Z", headers.get(HTTP_HEADER.VIA, ""), re.I) is not None
|
retval |= re.search(r"varnish\Z", headers.get(HTTP_HEADER.VIA, ""), re.I) is not None
|
||||||
|
retval |= re.search(r"varnish", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
|
retval |= code == 404 and re.search(r"\bXID: \d+", page or "") is not None
|
||||||
if retval:
|
if retval:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user