Skip to content

Commit

Permalink
Ajout d'une option d'authentification
Browse files Browse the repository at this point in the history
Ajout d'une option pour faire l'authentification à partir d'un fichier .side
  • Loading branch information
OussamaBeng committed Sep 13, 2024
1 parent 724f726 commit e16d6b0
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 6 deletions.
8 changes: 7 additions & 1 deletion doc/wapiti.1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "WAPITI" "1" "August 2024" "" ""
.TH "WAPITI" "1" "September 2024" "" ""
.
.SH "NAME"
\fBwapiti\fR \- A web application vulnerability scanner in Python
Expand Down Expand Up @@ -98,6 +98,9 @@ PROXY AND AUTHENTICATION OPTIONS:
\fB\-\-form\-script\fR \fIFILENAME\fR
.
.IP "\(bu" 4
\fB\-\-side\-file\fR \fIFILENAME\fR
.
.IP "\(bu" 4
\fB\-c\fR, \fB\-\-cookie\fR \fICOOKIE_FILE_OR_BROWSER_NAME\fR
.
.IP "\(bu" 4
Expand Down Expand Up @@ -436,6 +439,9 @@ Send data specified with \fB\-\-form\-data\fR using the given content\-type (def
Use a custom Python authentication plugin
.
.IP "\(bu" 4
\fB\-\-side\-file\fR \fIFILENAME\fR Use a \.side file generated using Selenium IDE to perform an authenticated scan\.
.
.IP "\(bu" 4
\fB\-c\fR, \fB\-\-cookie\fR \fICOOKIE_FILE_OR_BROWSER_NAME\fR
.
.br
Expand Down
5 changes: 4 additions & 1 deletion doc/wapiti.1.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions doc/wapiti.ronn
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ PROXY AND AUTHENTICATION OPTIONS:
* `--form-url` <URL>
* `--form-enctype` <ENCTYPE>
* `--form-script` <FILENAME>
* `--side-file` <FILENAME>
* `-c`, `--cookie` <COOKIE_FILE_OR_BROWSER_NAME>
* `-C`, `--cookie-value` <COOKIE_VALUE>
* `--drop-set-cookie`
Expand Down Expand Up @@ -199,6 +200,9 @@ OTHER OPTIONS:
* `--form-script` <FILENAME>
Use a custom Python authentication plugin

* `--side-file` <FILENAME>
Use a .side file generated using Selenium IDE to perform an authenticated scan.

* `-c`, `--cookie` <COOKIE_FILE_OR_BROWSER_NAME>
Load cookies from a Wapiti JSON cookie file. See wapiti-getcookie(1) for more information.
You can also import cookies from your browser by passing "chrome" or "firefox" as value (MS Edge is not supported).
Expand Down
9 changes: 8 additions & 1 deletion wapitiCore/main/wapiti.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
from wapitiCore.parsers.commandline import parse_args
from wapitiCore.main.log import logging
from wapitiCore.net.classes import HttpCredential, FormCredential, RawCredential
from wapitiCore.net.auth import async_try_form_login, load_form_script, check_http_auth, login_with_raw_data
from wapitiCore.net.auth import (async_try_form_login, load_form_script, check_http_auth, login_with_raw_data,
authenticate_with_side_file)
from wapitiCore.net import Request
from wapitiCore.report import GENERATORS
from wapitiCore.parsers.swagger import Swagger
Expand Down Expand Up @@ -235,6 +236,12 @@ async def wapiti_main():
wap.set_headless(args.headless)
wap.set_wait_time(args.wait_time)

if "side_file" in args:
if os.path.isfile(args.side_file):
wap.crawler_configuration.cookies = await authenticate_with_side_file(
wap.crawler_configuration, args.side_file, args.headless
)

if "cookie" in args:
if os.path.isfile(args.cookie):
wap.set_cookie_file(args.cookie)
Expand Down
111 changes: 108 additions & 3 deletions wapitiCore/net/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
import json
from http.cookiejar import CookieJar
from typing import Tuple, List, Dict, Optional
import asyncio
from urllib.parse import urlparse
import importlib.util

from httpx import RequestError
from arsenic import get_session, browsers, services
from arsenic.errors import ArsenicError
from arsenic import get_session, browsers, services, errors, constants

from wapitiCore.net import Request, Response
from wapitiCore.parsers.html_parser import Html
Expand Down Expand Up @@ -118,7 +119,7 @@ async def async_fetch_login_page(
page_source = await headless_client.get_page_source()
crawler_configuration.cookies = headless_cookies_to_cookiejar(await headless_client.get_all_cookies())
return page_source
except (ArsenicError, asyncio.TimeoutError) as exception:
except (errors.ArsenicError, asyncio.TimeoutError) as exception:
logging.error(f"[!] {exception.__class__.__name__} with URL {url}")
return
else:
Expand Down Expand Up @@ -238,3 +239,107 @@ async def load_form_script(
sys.exit(1)
except TypeError as exception:
raise RuntimeError("The provided auth script seems to have some syntax issues") from exception


async def authenticate_with_side_file(
crawler_configuration: CrawlerConfiguration,
side_file_path: str,
headless_value: str
) -> Optional[CookieJar]:
"""
Authenticate using a .side file.
"""
# Load and parse the .side file
with open(side_file_path, 'r', encoding='utf-8') as file:
try:
side_data = json.load(file)
except json.JSONDecodeError as json_error:
raise ValueError("The file content is not valid JSON.") from json_error

url = side_data['url']
login_test = side_data['tests'][0] # Assuming the first test is the login test

proxy_settings = None
if crawler_configuration.proxy:
proxy = urlparse(crawler_configuration.proxy).netloc
proxy_settings = {
"proxyType": 'manual',
"httpProxy": proxy,
"sslProxy": proxy
}

service = services.Geckodriver()
browser = browsers.Firefox(
proxy=proxy_settings,
acceptInsecureCerts=True,
**{
"moz:firefoxOptions": {
"prefs": {
"network.proxy.allow_hijacking_localhost": True,
"devtools.jsonview.enabled": False,
},
"args": ["-headless"] if headless_value in ["hidden", "no"] else [],
}
}
)

try:
async with get_session(service, browser) as headless_client:
for command in login_test['commands']:
await asyncio.sleep(3)
cmd = command['command']
target = command['target']
value = command.get('value', '')

if cmd == "open":
await headless_client.get(url + target)

elif cmd == "type":
if target.startswith("id="):
selector_value = target.split("=", 1)[1]
element = await headless_client.get_element(
f"#{selector_value}", constants.SelectorType.css_selector
)
elif target.startswith("css="):
selector_value = target.split("=", 1)[1]
element = await headless_client.get_element(
selector_value, constants.SelectorType.css_selector
)
elif target.startswith("xpath="):
selector_value = target.split("=", 1)[1]
element = await headless_client.get_element(
selector_value, constants.SelectorType.xpath
)
else:
raise ValueError(f"Unknown selector type: {target}")

await element.send_keys(value)

elif cmd == "click":
if target.startswith("id="):
selector_value = target.split("=", 1)[1]
element = await headless_client.get_element(
f"#{selector_value}", constants.SelectorType.css_selector
)
elif target.startswith("css="):
selector_value = target.split("=", 1)[1]
element = await headless_client.get_element(
selector_value, constants.SelectorType.css_selector
)
elif target.startswith("xpath="):
selector_value = target.split("=", 1)[1]
element = await headless_client.get_element(
selector_value, constants.SelectorType.xpath
)
else:
raise ValueError(f"Unknown selector type: {target}")
await element.click()

await asyncio.sleep(.1)
crawler_configuration.cookies = headless_cookies_to_cookiejar(await headless_client.get_all_cookies())

return crawler_configuration.cookies


except (errors.ArsenicError, asyncio.TimeoutError) as exception:
logging.error(f"[!] {exception.__class__.__name__} with URL {url}")
1 change: 1 addition & 0 deletions wapitiCore/net/intercepting_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ async def launch_headless_explorer(
while to_explore and not stop_event.is_set():
request = to_explore.popleft()
excluded_requests.append(request)
request.set_cookies(crawler.cookie_jar)

if request.method == "GET":
try:
Expand Down
10 changes: 10 additions & 0 deletions wapitiCore/parsers/commandline.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,16 @@ def parse_args():
metavar="COOKIE_FILE"
)

parser.add_argument(
"-sf", "--side-file",
help=(
"Set a JSON cookie file to use. "
"You can also pass 'firefox' or 'chrome' to load cookies from your browser."
),
default=argparse.SUPPRESS,
metavar="SIDE_FILE"
)

parser.add_argument(
"-C", "--cookie-value",
default=argparse.SUPPRESS,
Expand Down

0 comments on commit e16d6b0

Please sign in to comment.