Skip to content

Commit 56e2755

Browse files
committed
Merged master.
1 parent 04b293d commit 56e2755

File tree

7 files changed

+174
-22
lines changed

7 files changed

+174
-22
lines changed

data/txt/sha256sums.txt

+6-7
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ e050353f74c0baaf906ffca91dd04591645455ae363ae732a7a23f91ffe2ef1c lib/core/datat
174174
bdd1b5b3eb42cffdc1be78b8fe4e1bb2ec17cd86440a7aeb08fc599205089e94 lib/core/decorators.py
175175
9219f0bd659e4e22f4238ca67830adcb1e86041ce7fd3a8ae0e842f2593ae043 lib/core/defaults.py
176176
ec8d94fb704c0a40c88f5f283624cda025e2ea0e8b68722fe156c2b5676f53ac lib/core/dicts.py
177-
65fb5a2fc7b3bb502cc2db684370f213ab76bff875f3cf72ef2b9ace774efda9 lib/core/dump.py
178-
0e28c66ea9dfa1b721cfca63c364bdc139f53ebc8f9c57126b0af7dc6b433dcc lib/core/enums.py
177+
2070b406f123e4cc2b0015d125947c48b5f9afcb976ffaba9534841d30325310 lib/core/dump.py
178+
d653ec01dfa47ee93d2ffe53b1ab76b3a4fb649f517f9f6572a38186882e0255 lib/core/enums.py
179179
64bf6a5c2e456306a7b4f4c51f077412daf6c697fed232d8e23b77fd1a4c736e lib/core/exception.py
180180
93c256111dc753967169988e1289a0ea10ec77bfb8e2cbd1f6725e939bfbc235 lib/core/gui.py
181181
1d6e741e19e467650dce2ca84aa824d6df68ff74aedbe4afa8dbdb0193d94918 lib/core/__init__.py
@@ -188,7 +188,7 @@ c6a182f6b7d3b0ad6f0888ea2a4de4148f0770549038d7de8bc3267b4c6635f7 lib/core/readl
188188
63ae69713c6ea9abfa10e71dfab8f2dcf42432177a38d2c1e98785bf1468674c lib/core/replication.py
189189
5bad5bc7115051cef7b84efa73fbafbf5e1db46eef32a445056b56cda750b66f lib/core/revision.py
190190
0dcb52c9c76a4b0acf2e9038f7d8f08c14543cef3cf7032831c6c0a99376ad24 lib/core/session.py
191-
f04c8a49a6c7205949d54bed4226abf8ab97361ceb4e0325fc260456a0ad412f lib/core/settings.py
191+
fffc75cd873d5d75436e24a0121492e08a436846673ff43fffc3b2173162ff94 lib/core/settings.py
192192
a1e4f2860bffc73bbf2e5db293fa49dcb600ea35f950cda43dc953b3160ab3db lib/core/shell.py
193193
841716e87b90a3b598515910841f7cf8d33bb87c24a27fba1a80e36a831cbcd7 lib/core/subprocessng.py
194194
9731092f195e346716929323ea3c93247b23b9b92b0f32d3fd0acc3adf9876cc lib/core/target.py
@@ -199,7 +199,7 @@ b1071f449a66b4ceacd4b84b33a73d9e0a3197d271d72daaa406ba473a8bb625 lib/core/testi
199199
12cbead4e9e563b970fafb891127927445bd53bada1fac323b9cd27da551ba30 lib/core/wordlist.py
200200
1d6e741e19e467650dce2ca84aa824d6df68ff74aedbe4afa8dbdb0193d94918 lib/__init__.py
201201
a027f4c44811cb74aa367525f353706de3d3fc719e6c6162f7a61dc838acf0c2 lib/parse/banner.py
202-
2838467a296a05c6c94ddef1f42f1e7cddee3a9e755143bcb70129233056abad lib/parse/cmdline.py
202+
947be08682b822eebc14caf0cf9b8f8c089a737ea511147d7262eb03b28c5f0b lib/parse/cmdline.py
203203
3907765df08c31f8d59350a287e826bd315a7714dc0e87496f67c8a0879c86ac lib/parse/configfile.py
204204
ced03337edd5a16b56a379c9ac47775895e1053003c25f6ba5bec721b6e3aa64 lib/parse/handler.py
205205
3704a02dcf00b0988b101e30b2e0d48acdd20227e46d8b552e46c55d7e9bf28c lib/parse/headers.py
@@ -476,8 +476,8 @@ b3d9d0644197ecb864e899c04ee9c7cd63891ecf2a0d3c333aad563eef735294 plugins/generi
476476
5a473c60853f54f1a4b14d79b8237f659278fe8a6b42e935ed573bf22b6d5b2c README.md
477477
8c4fd81d84598535643cf0ef1b2d350cd92977cb55287e23993b76eaa2215c30 sqlmapapi.py
478478
168309215af7dd5b0b71070e1770e72f1cbb29a3d8025143fb8aa0b88cd56b62 sqlmapapi.yaml
479-
4037f1c78180550c1896543581c0c2423e970086bae46f175397f2b4c54b7323 sqlmap.conf
480-
f84846b8493d809d697a75b3d13d904013bbb03e0edd82b724f4753801609057 sqlmap.py
479+
002d27074b16fb864cbecfc2a065357e2727c43086bdf87c72979fa35f9b4ca3 sqlmap.conf
480+
6d75a4879385977c799852744a309d6f19c3155c7a5e9fd48633df48d80e4451 sqlmap.py
481481
9d408612a6780f7f50a7f7887f923ff3f40be5bfa09a951c6dc273ded05b56c0 tamper/0eunion.py
482482
c1c2eaa7df016cc7786ccee0ae4f4f363b1dce139c61fb3e658937cb0d18fc54 tamper/apostrophemask.py
483483
19023093ab22aec3bce9523f28e8111e8f6125973e6d9c82adb60da056bdf617 tamper/apostrophenullencode.py
@@ -511,7 +511,6 @@ d498e409c96d2ae2cc86263ead52ae385e95e9ec27f28247180c7c73ec348b3f tamper/informa
511511
1d6e741e19e467650dce2ca84aa824d6df68ff74aedbe4afa8dbdb0193d94918 tamper/__init__.py
512512
b9a84211c84785361f4efa55858a1cdddd63cee644d0b8d4323b3a5e3db7d12f tamper/least.py
513513
0de2bd766f883ac742f194f991c5d38799ffbf4346f4376be7ec8d750f2d9ef8 tamper/lowercase.py
514-
5015f35181dd4e4e0bddc67c4dfd86d6c509ae48a5f0212a122ff9a62f7352ce tamper/luanginxmore.py
515514
c390d072ed48431ab5848d51b9ca5c4ff323964a770f0597bdde943ed12377f8 tamper/luanginx.py
516515
7eba10540514a5bfaee02e92b711e0f89ffe30b1672ec25c7680f2aa336c8a58 tamper/misunion.py
517516
b262da8d38dbb4be64d42e0ab07e25611da11c5d07aa11b09497b344a4c76b8d tamper/modsecurityversioned.py

lib/core/dump.py

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
from lib.core.replication import Replication
4848
from lib.core.settings import DUMP_FILE_BUFFER_SIZE
4949
from lib.core.settings import HTML_DUMP_CSS_STYLE
50+
from lib.core.settings import HTML_DUMP_CSS_SORTABLE_STYLE
51+
from lib.core.settings import HTML_DUMP_SORTABLE_JAVASCRIPT
5052
from lib.core.settings import IS_WIN
5153
from lib.core.settings import METADB_SUFFIX
5254
from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE
@@ -541,6 +543,9 @@ def dbTableValues(self, tableValues):
541543
dataToDumpFile(dumpFP, "<meta name=\"generator\" content=\"%s\" />\n" % VERSION_STRING)
542544
dataToDumpFile(dumpFP, "<title>%s</title>\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table)))
543545
dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE)
546+
if conf.dumpSortable:
547+
dataToDumpFile(dumpFP, HTML_DUMP_CSS_SORTABLE_STYLE)
548+
dataToDumpFile(dumpFP, HTML_DUMP_SORTABLE_JAVASCRIPT)
544549
dataToDumpFile(dumpFP, "\n</head>\n<body>\n<table>\n<thead>\n<tr>\n")
545550

546551
if count == 1:

lib/core/enums.py

+1
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class REGISTRY_OPERATION(object):
229229
class DUMP_FORMAT(object):
230230
CSV = "CSV"
231231
HTML = "HTML"
232+
SORTABLE_HTML = "SORTABLE_HTML"
232233
SQLITE = "SQLITE"
233234

234235
class HTTP_HEADER(object):

lib/core/settings.py

+147-13
Original file line numberDiff line numberDiff line change
@@ -918,29 +918,163 @@
918918

919919
# CSS style used in HTML dump format
920920
HTML_DUMP_CSS_STYLE = """<style>
921-
table{
922-
margin:10;
923-
background-color:#FFFFFF;
924-
font-family:verdana;
925-
font-size:12px;
926-
align:center;
921+
table {
922+
margin: 10px;
923+
background: #fff;
924+
font: 12px verdana;
925+
text-align: center;
927926
}
928927
thead{
929928
font-weight:bold;
930929
background-color:#4F81BD;
931-
color:#FFFFFF;
930+
color: #fff;
932931
}
933932
tr:nth-child(even) {
934-
background-color: #D3DFEE
933+
background-color: #D3DFEE;
935934
}
936-
td{
937-
font-size:12px;
935+
</style>"""
936+
937+
HTML_DUMP_CSS_SORTABLE_STYLE = """
938+
<style>
939+
table thead th {
940+
cursor: pointer;
941+
white-space: nowrap;
942+
position: sticky;
943+
top: 0;
944+
z-index: 1;
938945
}
939-
th{
940-
font-size:12px;
946+
947+
table thead th::after,
948+
table thead th::before {
949+
color: transparent;
950+
}
951+
952+
table thead th::after {
953+
margin-left: 3px;
954+
content: "▸";
955+
}
956+
957+
table thead th:hover::after,
958+
table thead th[aria-sort]::after {
959+
color: inherit;
960+
}
961+
962+
table thead th[aria-sort=descending]::after {
963+
content: "▾";
941964
}
942-
</style>"""
943965
966+
table thead th[aria-sort=ascending]::after {
967+
content: "▴";
968+
}
969+
970+
table thead th.indicator-left::before {
971+
margin-right: 3px;
972+
content: "▸";
973+
}
974+
975+
table thead th.indicator-left[aria-sort=descending]::before {
976+
color: inherit;
977+
content: "▾";
978+
}
979+
980+
table thead th.indicator-left[aria-sort=ascending]::before {
981+
color: inherit;
982+
content: "▴";
983+
}
984+
</style>
985+
"""
986+
HTML_DUMP_SORTABLE_JAVASCRIPT = """<script>
987+
window.addEventListener('DOMContentLoaded', () => {
988+
document.addEventListener('click', event => {
989+
try {
990+
const isAltSort = event.shiftKey || event.altKey;
991+
992+
// Find the clicked table header
993+
const findParentElement = (element, nodeName) =>
994+
element.nodeName === nodeName ? element : findParentElement(element.parentNode, nodeName);
995+
996+
const headerCell = findParentElement(event.target, 'TH');
997+
const headerRow = headerCell.parentNode;
998+
const thead = headerRow.parentNode;
999+
const table = thead.parentNode;
1000+
1001+
if (thead.nodeName !== 'THEAD') return;
1002+
1003+
// Reset sort indicators on other headers
1004+
Array.from(headerRow.cells).forEach(cell => {
1005+
if (cell !== headerCell) cell.removeAttribute('aria-sort');
1006+
});
1007+
1008+
// Toggle sort direction
1009+
const currentSort = headerCell.getAttribute('aria-sort');
1010+
const isAscending = table.classList.contains('asc') && currentSort !== 'ascending';
1011+
const sortDirection = (currentSort === 'descending' || isAscending) ? 'ascending' : 'descending';
1012+
headerCell.setAttribute('aria-sort', sortDirection);
1013+
1014+
// Debounce sort operation
1015+
if (table.dataset.timer) clearTimeout(Number(table.dataset.timer));
1016+
1017+
table.dataset.timer = setTimeout(() => {
1018+
sortTable(table, isAltSort);
1019+
}, 1).toString();
1020+
} catch (error) {
1021+
console.error('Sorting error:', error);
1022+
}
1023+
});
1024+
});
1025+
1026+
function sortTable(table, useAltSort) {
1027+
table.dispatchEvent(new CustomEvent('sort-start', { bubbles: true }));
1028+
1029+
const sortHeader = table.tHead.querySelector('th[aria-sort]');
1030+
const headerRow = table.tHead.children[0];
1031+
const isAscending = sortHeader.getAttribute('aria-sort') === 'ascending';
1032+
const shouldPushEmpty = table.classList.contains('n-last');
1033+
const sortColumnIndex = Number(sortHeader.dataset.sortCol ?? sortHeader.cellIndex);
1034+
1035+
const getCellValue = cell => {
1036+
if (useAltSort) return cell.dataset.sortAlt;
1037+
return cell.dataset.sort ?? cell.textContent;
1038+
};
1039+
1040+
const compareRows = (row1, row2) => {
1041+
const value1 = getCellValue(row1.cells[sortColumnIndex]);
1042+
const value2 = getCellValue(row2.cells[sortColumnIndex]);
1043+
1044+
// Handle empty values
1045+
if (shouldPushEmpty) {
1046+
if (value1 === '' && value2 !== '') return -1;
1047+
if (value2 === '' && value1 !== '') return 1;
1048+
}
1049+
1050+
// Compare numerically if possible, otherwise use string comparison
1051+
const numericDiff = Number(value1) - Number(value2);
1052+
const comparison = isNaN(numericDiff) ?
1053+
value1.localeCompare(value2, undefined, { numeric: true }) :
1054+
numericDiff;
1055+
1056+
// Handle tiebreaker
1057+
if (comparison === 0 && headerRow.cells[sortColumnIndex]?.dataset.sortTbr) {
1058+
const tiebreakIndex = Number(headerRow.cells[sortColumnIndex].dataset.sortTbr);
1059+
return compareRows(row1, row2, tiebreakIndex);
1060+
}
1061+
1062+
return isAscending ? -comparison : comparison;
1063+
};
1064+
1065+
// Sort each tbody
1066+
Array.from(table.tBodies).forEach(tbody => {
1067+
const rows = Array.from(tbody.rows);
1068+
const sortedRows = rows.sort(compareRows);
1069+
1070+
const newTbody = tbody.cloneNode();
1071+
newTbody.append(...sortedRows);
1072+
tbody.replaceWith(newTbody);
1073+
});
1074+
1075+
table.dispatchEvent(new CustomEvent('sort-end', { bubbles: true }));
1076+
}
1077+
</script>"""
9441078
# Leaving (dirty) possibility to change values from here (e.g. `export SQLMAP__MAX_NUMBER_OF_THREADS=20`)
9451079
for key, value in os.environ.items():
9461080
if key.upper().startswith("%s_" % SQLMAP_ENVIRONMENT_PREFIX):

lib/parse/cmdline.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ def cmdLineParser(argv=None):
677677
help="Store dumped data to a custom file")
678678

679679
general.add_argument("--dump-format", dest="dumpFormat",
680-
help="Format of dumped data (CSV (default), HTML or SQLITE)")
680+
help="Format of dumped data (CSV (default), HTML, SORTABLE_HTML or SQLITE)")
681681

682682
general.add_argument("--encoding", dest="encoding",
683683
help="Character encoding used for data retrieval (e.g. GBK)")
@@ -857,6 +857,9 @@ def cmdLineParser(argv=None):
857857
parser.add_argument("--smoke-test", dest="smokeTest", action="store_true",
858858
help=SUPPRESS)
859859

860+
parser.add_argument("--update-sums", dest="updateSums", action="store_true",
861+
help=SUPPRESS)
862+
860863
parser.add_argument("--vuln-test", dest="vulnTest", action="store_true",
861864
help=SUPPRESS)
862865

sqlmap.conf

+2-1
Original file line numberDiff line numberDiff line change
@@ -758,9 +758,10 @@ csvDel = ,
758758
dumpFile =
759759

760760
# Format of dumped data
761-
# Valid: CSV, HTML or SQLITE
761+
# Valid: CSV, HTML, SORTABLE_HTML or SQLITE
762762
dumpFormat = CSV
763763

764+
dumpSortable = False
764765
# Force character encoding used for data retrieval.
765766
encoding =
766767

sqlmap.py

+9
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ def main():
158158
if checkPipedInput():
159159
conf.batch = True
160160

161+
if conf.get("dumpFormat") == "SORTABLE_HTML":
162+
conf.dumpFormat = "HTML"
163+
conf.dumpSortable = True
164+
else:
165+
conf.dumpSortable = False
166+
161167
if conf.get("api"):
162168
# heavy imports
163169
from lib.utils.api import StdDbOut
@@ -179,6 +185,9 @@ def main():
179185
if not conf.updateAll:
180186
# Postponed imports (faster start)
181187
if conf.smokeTest:
188+
if conf.updateSums:
189+
from lib.core.common import updateSums
190+
updateSums()
182191
from lib.core.testing import smokeTest
183192
os._exitcode = 1 - (smokeTest() or 0)
184193
elif conf.vulnTest:

0 commit comments

Comments
 (0)