2020-05-17 16:15:16 +02:00
|
|
|
"""
|
|
|
|
Run by the evaluator, tries to make a GET request to a given server
|
|
|
|
"""
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import random
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
import traceback
|
|
|
|
import urllib.request
|
|
|
|
|
|
|
|
import requests
|
|
|
|
|
|
|
|
socket.setdefaulttimeout(1)
|
|
|
|
|
|
|
|
import external_sites
|
|
|
|
import actions.utils
|
|
|
|
|
|
|
|
from plugins.plugin_client import ClientPlugin
|
|
|
|
|
|
|
|
BASEPATH = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
|
|
|
|
|
|
class HTTPClient(ClientPlugin):
|
|
|
|
"""
|
|
|
|
Defines the HTTP client.
|
|
|
|
"""
|
|
|
|
name = "http"
|
|
|
|
|
|
|
|
def __init__(self, args):
|
|
|
|
"""
|
|
|
|
Initializes the HTTP client.
|
|
|
|
"""
|
|
|
|
ClientPlugin.__init__(self)
|
|
|
|
self.args = args
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def get_args(command):
|
|
|
|
"""
|
|
|
|
Defines required args for this plugin
|
|
|
|
"""
|
|
|
|
super_args = ClientPlugin.get_args(command)
|
|
|
|
parser = argparse.ArgumentParser(description='HTTP Client', prog="http/client.py")
|
|
|
|
|
|
|
|
parser.add_argument('--host-header', action='store', default="", help='specifies host header for HTTP request')
|
|
|
|
parser.add_argument('--injected-http-contains', action='store', default="", help='checks if injected http response contains string')
|
|
|
|
|
|
|
|
args, _ = parser.parse_known_args(command)
|
|
|
|
args = vars(args)
|
|
|
|
|
|
|
|
super_args.update(args)
|
|
|
|
return super_args
|
|
|
|
|
|
|
|
def run(self, args, logger, engine=None):
|
|
|
|
"""
|
|
|
|
Try to make a forbidden GET request to the server.
|
|
|
|
"""
|
|
|
|
fitness = 0
|
|
|
|
url = args.get("server", "")
|
|
|
|
assert url, "Cannot launch HTTP test with no server"
|
|
|
|
if not url.startswith("http://"):
|
|
|
|
url = "http://" + url
|
|
|
|
headers = {}
|
|
|
|
if args.get('host_header'):
|
|
|
|
headers["Host"] = args.get('host_header')
|
|
|
|
|
|
|
|
# If we've been given a non-standard port, append that to the URL
|
|
|
|
port = args.get("port", 80)
|
|
|
|
if port != 80:
|
|
|
|
url += ":%s" % str(port)
|
|
|
|
|
2020-10-10 19:40:54 +02:00
|
|
|
if args.get("bad_word"):
|
|
|
|
url += "?q=%s" % args.get("bad_word")
|
2020-05-17 16:15:16 +02:00
|
|
|
|
|
|
|
injected_http = args.get("injected_http_contains")
|
|
|
|
try:
|
|
|
|
res = requests.get(url, allow_redirects=False, timeout=3, headers=headers)
|
|
|
|
logger.debug(res.text)
|
|
|
|
# If we need to monitor for an injected response, check that here
|
|
|
|
if injected_http and injected_http in res.text:
|
|
|
|
fitness -= 90
|
|
|
|
else:
|
|
|
|
fitness += 100
|
2020-10-18 15:51:22 +02:00
|
|
|
except requests.exceptions.ConnectTimeout as exc:
|
|
|
|
logger.exception("Socket timeout.")
|
|
|
|
fitness -= 100
|
2020-05-17 16:15:16 +02:00
|
|
|
except (requests.exceptions.ConnectionError, ConnectionResetError) as exc:
|
|
|
|
logger.exception("Connection RST.")
|
|
|
|
fitness -= 90
|
|
|
|
except urllib.error.URLError as exc:
|
|
|
|
logger.debug(exc)
|
|
|
|
fitness += -101
|
|
|
|
# Timeouts generally mean the strategy killed the TCP stream.
|
|
|
|
# HTTPError usually mean the request was destroyed.
|
|
|
|
# Punish this more harshly than getting caught by the censor.
|
|
|
|
except (requests.exceptions.Timeout, requests.exceptions.HTTPError) as exc:
|
|
|
|
logger.debug(exc)
|
|
|
|
fitness += -120
|
|
|
|
except Exception:
|
|
|
|
logger.exception("Exception caught in HTTP test to site %s.", url)
|
|
|
|
fitness += -100
|
|
|
|
return fitness * 4
|