예제 #1
0
파일: main.py 프로젝트: modulexcite/commix
def main(filename, url):
    try:
        # Ignore the mathematic calculation part (Detection phase).
        if menu.options.skip_calc:
            settings.SKIP_CALC = True

        if menu.options.enable_backticks:
            settings.USE_BACKTICKS = True

        # Target URL reload.
        if menu.options.url_reload and menu.options.data:
            settings.URL_RELOAD = True

        if menu.options.test_parameter and menu.options.skip_parameter:
            if type(menu.options.test_parameter) is bool:
                menu.options.test_parameter = None
            else:
                err_msg = "The options '-p' and '--skip' cannot be used "
                err_msg += "simultaneously (i.e. only one option must be set)."
                print settings.print_critical_msg(err_msg)
                raise SystemExit

        # Ignore session
        if menu.options.ignore_session:
            session_handler.ignore(url)

        # Check provided parameters for tests
        if menu.options.test_parameter or menu.options.skip_parameter:
            if menu.options.test_parameter != None:
                if menu.options.test_parameter.startswith("="):
                    menu.options.test_parameter = menu.options.test_parameter[
                        1:]
                settings.TEST_PARAMETER = menu.options.test_parameter.split(
                    settings.PARAMETER_SPLITTING_REGEX)

            elif menu.options.skip_parameter != None:
                if menu.options.skip_parameter.startswith("="):
                    menu.options.skip_parameter = menu.options.skip_parameter[
                        1:]
                settings.TEST_PARAMETER = menu.options.skip_parameter.split(
                    settings.PARAMETER_SPLITTING_REGEX)

            for i in range(0, len(settings.TEST_PARAMETER)):
                if "=" in settings.TEST_PARAMETER[i]:
                    settings.TEST_PARAMETER[i] = settings.TEST_PARAMETER[
                        i].split("=")[0]

        # Check injection level, due to the provided testable parameters.
        if menu.options.level < 2 and menu.options.test_parameter != None:
            checks.check_injection_level()

        # Check if defined character used for splitting cookie values.
        if menu.options.cdel:
            settings.COOKIE_DELIMITER = menu.options.cdel

        # Check for skipping injection techniques.
        if menu.options.skip_tech:
            if menu.options.tech:
                err_msg = "The options '--technique' and '--skip-technique' cannot be used "
                err_msg += "simultaneously (i.e. only one option must be set)."
                print settings.print_critical_msg(err_msg)
                raise SystemExit

            settings.SKIP_TECHNIQUES = True
            menu.options.tech = menu.options.skip_tech

        # Check if specified wrong injection technique
        if menu.options.tech and menu.options.tech not in settings.AVAILABLE_TECHNIQUES:
            found_tech = False

            # Convert injection technique(s) to lowercase
            menu.options.tech = menu.options.tech.lower()

            # Check if used the ',' separator
            if settings.PARAMETER_SPLITTING_REGEX in menu.options.tech:
                split_techniques_names = menu.options.tech.split(
                    settings.PARAMETER_SPLITTING_REGEX)
            else:
                split_techniques_names = menu.options.tech.split()
            if split_techniques_names:
                for i in range(0, len(split_techniques_names)):
                    if len(menu.options.tech) <= 4:
                        split_first_letter = list(menu.options.tech)
                        for j in range(0, len(split_first_letter)):
                            if split_first_letter[
                                    j] in settings.AVAILABLE_TECHNIQUES:
                                found_tech = True
                            else:
                                found_tech = False

            if split_techniques_names[i].replace(' ', '') not in settings.AVAILABLE_TECHNIQUES and \
               found_tech == False:
                err_msg = "You specified wrong value '" + split_techniques_names[
                    i]
                err_msg += "' as injection technique. "
                err_msg += "The value for '"
                if not settings.SKIP_TECHNIQUES:
                    err_msg += "--technique"
                else:
                    err_msg += "--skip-technique"

                err_msg += "' must be a string composed by the letters C, E, T, F. "
                err_msg += "Refer to the official wiki for details."
                print settings.print_critical_msg(err_msg)
                raise SystemExit()

        # Check if specified wrong alternative shell
        if menu.options.alter_shell:
            if menu.options.alter_shell.lower(
            ) not in settings.AVAILABLE_SHELLS:
                err_msg = "'" + menu.options.alter_shell + "' shell is not supported!"
                print settings.print_critical_msg(err_msg)
                raise SystemExit()

        # Check the file-destination
        if menu.options.file_write and not menu.options.file_dest or \
        menu.options.file_upload  and not menu.options.file_dest:
            err_msg = "Host's absolute filepath to write and/or upload, must be specified (i.e. '--file-dest')."
            print settings.print_critical_msg(err_msg)
            raise SystemExit()

        if menu.options.file_dest and menu.options.file_write == None and menu.options.file_upload == None:
            err_msg = "You must enter the '--file-write' or '--file-upload' parameter."
            print settings.print_critical_msg(err_msg)
            raise SystemExit()

        # Check if defined "--url" or "-m" option.
        if url:
            # Load the crawler
            if menu.options.crawldepth > 0 or menu.options.sitemap_url:
                url = crawler.crawler(url)
            try:
                if menu.options.flush_session:
                    session_handler.flush(url)
                # Check for CGI scripts on url
                checks.check_CGI_scripts(url)
                # Used a valid pair of valid credentials
                if menu.options.auth_cred:
                    success_msg = Style.BRIGHT + "Identified a valid pair of credentials '"
                    success_msg += menu.options.auth_cred + Style.RESET_ALL
                    success_msg += Style.BRIGHT + "'." + Style.RESET_ALL
                    print settings.print_success_msg(success_msg)
                # Modification on payload
                if not menu.options.shellshock:
                    if not settings.USE_BACKTICKS:
                        settings.SYS_USERS = "echo $(" + settings.SYS_USERS + ")"
                        settings.SYS_PASSES = "echo $(" + settings.SYS_PASSES + ")"
                # Check if defined "--file-upload" option.
                if menu.options.file_upload:
                    checks.file_upload()
                    try:
                        urllib2.urlopen(menu.options.file_upload)
                    except urllib2.HTTPError, err_msg:
                        print settings.print_critical_msg(str(err_msg.code))
                        raise SystemExit()
                    except urllib2.URLError, err_msg:
                        print settings.print_critical_msg(
                            str(err_msg.args[0]).split("] ")[1] + ".")
                        raise SystemExit()
                try:
                    # Webpage encoding detection.
                    requests.encoding_detection(response)
                    if response.info()['server']:
                        server_banner = response.info()['server']
                        # Procedure for target server's operating system identification.
                        requests.check_target_os(server_banner)
                        # Procedure for target server identification.
                        requests.server_identification(server_banner)
                        # Procedure for target application identification
                        requests.application_identification(server_banner, url)
                        # Store the Server's root dir
                        settings.DEFAULT_WEB_ROOT = settings.WEB_ROOT
                        if menu.options.is_admin or menu.options.is_root and not menu.options.current_user:
                            menu.options.current_user = True
                        # Define Python working directory.
                        checks.define_py_working_dir()
                        # Check for wrong flags.
                        checks.check_wrong_flags()
                    else:
                        found_os_server = checks.user_defined_os()
                except KeyError:
                    pass
                # Load tamper scripts
                if menu.options.tamper:
                    checks.tamper_scripts()
예제 #2
0
파일: main.py 프로젝트: getdrive/commix
def main(filename, url):

    try:
        # Ignore the mathematic calculation part (Detection phase).
        if menu.options.skip_calc:
            settings.SKIP_CALC = True

        if menu.options.enable_backticks:
            settings.USE_BACKTICKS = True

        # Target URL reload.
        if menu.options.url_reload and menu.options.data:
            settings.URL_RELOAD = True

        if menu.options.header is not None and settings.INJECT_TAG in menu.options.header or \
           menu.options.headers is not None and settings.INJECT_TAG in menu.options.headers:
            info_msg = "Injection marker found in option '--header(s)/--user-agent/--referer/--cookie'."
            print(settings.print_info_msg(info_msg))
            if menu.options.test_parameter:
                err_msg = "The options '-p' and the injection marker cannot be used "
                err_msg += "simultaneously (i.e. only one option must be set)."
                print(settings.print_critical_msg(err_msg))
                raise SystemExit

        if menu.options.test_parameter and menu.options.skip_parameter:
            if type(menu.options.test_parameter) is bool:
                menu.options.test_parameter = None
            else:
                err_msg = "The options '-p' and '--skip' cannot be used "
                err_msg += "simultaneously (i.e. only one option must be set)."
                print(settings.print_critical_msg(err_msg))
                raise SystemExit

        if menu.options.ignore_session:
            # Ignore session
            session_handler.ignore(url)

        # Check provided parameters for tests
        if menu.options.test_parameter or menu.options.skip_parameter:
            if menu.options.test_parameter != None:
                if menu.options.test_parameter.startswith("="):
                    menu.options.test_parameter = menu.options.test_parameter[
                        1:]
                settings.TEST_PARAMETER = menu.options.test_parameter.split(
                    settings.PARAMETER_SPLITTING_REGEX)

            elif menu.options.skip_parameter != None:
                if menu.options.skip_parameter.startswith("="):
                    menu.options.skip_parameter = menu.options.skip_parameter[
                        1:]
                settings.TEST_PARAMETER = menu.options.skip_parameter.split(
                    settings.PARAMETER_SPLITTING_REGEX)

            for i in range(0, len(settings.TEST_PARAMETER)):
                if "=" in settings.TEST_PARAMETER[i]:
                    settings.TEST_PARAMETER[i] = settings.TEST_PARAMETER[
                        i].split("=")[0]

        # Check injection level, due to the provided testable parameters.
        if menu.options.level < 2 and menu.options.test_parameter != None:
            checks.check_injection_level()

        # Check if defined character used for splitting cookie values.
        if menu.options.cdel:
            settings.COOKIE_DELIMITER = menu.options.cdel

        # Check for skipping injection techniques.
        if menu.options.skip_tech:
            if menu.options.tech:
                err_msg = "The options '--technique' and '--skip-technique' cannot be used "
                err_msg += "simultaneously (i.e. only one option must be set)."
                print(settings.print_critical_msg(err_msg))
                raise SystemExit

            settings.SKIP_TECHNIQUES = True
            menu.options.tech = menu.options.skip_tech

        # Check if specified wrong injection technique
        if menu.options.tech and menu.options.tech not in settings.AVAILABLE_TECHNIQUES:
            found_tech = False

            # Convert injection technique(s) to lowercase
            menu.options.tech = menu.options.tech.lower()

            # Check if used the ',' separator
            if settings.PARAMETER_SPLITTING_REGEX in menu.options.tech:
                split_techniques_names = menu.options.tech.split(
                    settings.PARAMETER_SPLITTING_REGEX)
            else:
                split_techniques_names = menu.options.tech.split()
            if split_techniques_names:
                for i in range(0, len(split_techniques_names)):
                    if len(menu.options.tech) <= 4:
                        split_first_letter = list(menu.options.tech)
                        for j in range(0, len(split_first_letter)):
                            if split_first_letter[
                                    j] in settings.AVAILABLE_TECHNIQUES:
                                found_tech = True
                            else:
                                found_tech = False

            if split_techniques_names[i].replace(' ', '') not in settings.AVAILABLE_TECHNIQUES and \
               found_tech == False:
                err_msg = "You specified wrong value '" + split_techniques_names[
                    i]
                err_msg += "' as injection technique. "
                err_msg += "The value for '"
                if not settings.SKIP_TECHNIQUES:
                    err_msg += "--technique"
                else:
                    err_msg += "--skip-technique"

                err_msg += "' must be a string composed by the letters C, E, T, F. "
                err_msg += "Refer to the official wiki for details."
                print(settings.print_critical_msg(err_msg))
                raise SystemExit()

        # Check if specified wrong alternative shell
        if menu.options.alter_shell:
            if menu.options.alter_shell.lower(
            ) not in settings.AVAILABLE_SHELLS:
                err_msg = "'" + menu.options.alter_shell + "' shell is not supported!"
                print(settings.print_critical_msg(err_msg))
                raise SystemExit()

        # Check the file-destination
        if menu.options.file_write and not menu.options.file_dest or \
        menu.options.file_upload  and not menu.options.file_dest:
            err_msg = "Host's absolute filepath to write and/or upload, must be specified (i.e. '--file-dest')."
            print(settings.print_critical_msg(err_msg))
            raise SystemExit()

        if menu.options.file_dest and menu.options.file_write == None and menu.options.file_upload == None:
            err_msg = "You must enter the '--file-write' or '--file-upload' parameter."
            print(settings.print_critical_msg(err_msg))
            raise SystemExit()

        # Check if defined "--url" or "-m" option.
        if url:
            if menu.options.auth_cred and menu.options.auth_cred and settings.VERBOSITY_LEVEL >= 1:
                success_msg = "Used a valid pair of " + menu.options.auth_type
                success_msg += " HTTP authentication credentials '" + menu.options.auth_cred + "'."
                print(settings.print_success_msg(success_msg))
            # Load the crawler
            if menu.options.crawldepth > 0 or menu.options.sitemap_url:
                url = crawler.crawler(url)
            try:
                if menu.options.flush_session:
                    session_handler.flush(url)
                # Check for CGI scripts on url
                checks.check_CGI_scripts(url)
                # Modification on payload
                if not menu.options.shellshock:
                    if not settings.USE_BACKTICKS:
                        settings.SYS_USERS = "echo $(" + settings.SYS_USERS + ")"
                        settings.SYS_PASSES = "echo $(" + settings.SYS_PASSES + ")"
                # Check if defined "--file-upload" option.
                if menu.options.file_upload:
                    checks.file_upload()
                    try:
                        _urllib.request.urlopen(menu.options.file_upload)
                    except _urllib.error.HTTPError as err_msg:
                        print(settings.print_critical_msg(str(err_msg.code)))
                        raise SystemExit()
                    except _urllib.error.URLError as err_msg:
                        print(
                            settings.print_critical_msg(
                                str(err_msg.args[0]).split("] ")[1] + "."))
                        raise SystemExit()
                try:
                    # Webpage encoding detection.
                    requests.encoding_detection(response)
                    if response.info()['server']:
                        server_banner = response.info()['server']
                        # Procedure for target server's operating system identification.
                        requests.check_target_os(server_banner)
                        # Procedure for target server identification.
                        requests.server_identification(server_banner)
                        # Procedure for target application identification
                        requests.application_identification(server_banner, url)
                        # Store the Server's root dir
                        settings.DEFAULT_WEB_ROOT = settings.WEB_ROOT
                        if menu.options.is_admin or menu.options.is_root and not menu.options.current_user:
                            menu.options.current_user = True
                        # Define Python working directory.
                        checks.define_py_working_dir()
                        # Check for wrong flags.
                        checks.check_wrong_flags()
                    else:
                        found_os_server = checks.user_defined_os()
                except KeyError:
                    pass
                # Load tamper scripts
                if menu.options.tamper:
                    checks.tamper_scripts()

            except _urllib.error.HTTPError as err_msg:
                # Check the codes of responses
                if str(err_msg.getcode()) == settings.INTERNAL_SERVER_ERROR:
                    print("[ " + Fore.RED + "FAILED" + Style.RESET_ALL + " ]")
                    content = err_msg.read()
                    raise SystemExit()

                # Invalid permission to access target URL page.
                elif str(err_msg.getcode()) == settings.FORBIDDEN_ERROR:
                    if settings.VERBOSITY_LEVEL < 2:
                        print("[ " + Fore.RED + "FAILED" + Style.RESET_ALL +
                              " ]")
                    err_msg = "You don't have permission to access this page."
                    print(settings.print_critical_msg(err_msg))
                    raise SystemExit()

                # The target host seems to be down!
                elif str(err_msg.getcode()) == settings.NOT_FOUND_ERROR:
                    if settings.VERBOSITY_LEVEL < 2:
                        print("[ " + Fore.RED + "FAILED" + Style.RESET_ALL +
                              " ]")
                    err_msg = "The host seems to be down!"
                    print(settings.print_critical_msg(err_msg))
                    raise SystemExit()

                else:
                    raise

            # The target host seems to be down!
            except _urllib.error.URLError as e:
                if settings.VERBOSITY_LEVEL < 2:
                    print("[ " + Fore.RED + "FAILED" + Style.RESET_ALL + " ]")
                err_msg = "The host seems to be down"
                try:
                    err_msg += " (" + str(e.args[0]).split("] ")[1] + ")."
                except IndexError:
                    err_msg += "."
                    pass
                print(settings.print_critical_msg(err_msg))
                raise SystemExit()

            except _http_client.BadStatusLine as err_msg:
                if settings.VERBOSITY_LEVEL < 2:
                    print("[ " + Fore.RED + "FAILED" + Style.RESET_ALL + " ]")
                if len(err_msg.line) > 2:
                    print(err_msg.line, err_msg.message)
                pass

            except AttributeError:
                pass

        else:
            err_msg = "You must specify the target URL."
            print(settings.print_critical_msg(err_msg))
            raise SystemExit()

        # Retrieve everything from the supported enumeration options.
        if menu.options.enum_all:
            checks.enable_all_enumeration_options()

        # Launch injection and exploitation controller.
        controller.do_check(url, filename)
        return filename

    # Accidental stop / restart of the target host server.
    except _http_client.BadStatusLine as err_msg:
        if err_msg.line == "" or err_msg.message == "":
            err_msg = "The target host is not responding."
            err_msg += " Please ensure that is up and try again."
            print("\n\n" + settings.print_critical_msg(err_msg))
            logs.print_logs_notification(filename, url)
        else:
            err_msg = err_msg.line + err_msg.message
            print(settings.print_critical_msg(err_msg) + "\n")
        session_handler.clear(url)
        raise SystemExit()

    # Connection reset by peer
    except SocketError as err_msg:
        if settings.VERBOSITY_LEVEL >= 1:
            print("")
        err_msg = "The target host is not responding."
        err_msg += " Please ensure that is up and try again."
        print("\n" + settings.print_critical_msg(err_msg))
        logs.print_logs_notification(filename, url)
예제 #3
0
def main(filename, url):
  try:
    # Ignore the mathematic calculation part (Detection phase).
    if menu.options.skip_calc:
      settings.SKIP_CALC = True

    if menu.options.enable_backticks:
      settings.USE_BACKTICKS = True

    # Target URL reload.
    if menu.options.url_reload and menu.options.data:
      settings.URL_RELOAD = True

    if menu.options.test_parameter and menu.options.skip_parameter:
      if type(menu.options.test_parameter) is bool:
        menu.options.test_parameter = None
      else:
        err_msg = "The options '-p' and '--skip' cannot be used "
        err_msg += "simultaneously (i.e. only one option must be set)."
        print settings.print_critical_msg(err_msg)
        raise SystemExit

    if menu.options.ignore_session:
      # Ignore session
      session_handler.ignore(url)      

    # Check provided parameters for tests
    if menu.options.test_parameter or menu.options.skip_parameter:     
      if menu.options.test_parameter != None :
        if menu.options.test_parameter.startswith("="):
          menu.options.test_parameter = menu.options.test_parameter[1:]
        settings.TEST_PARAMETER = menu.options.test_parameter.split(settings.PARAMETER_SPLITTING_REGEX)  
      
      elif menu.options.skip_parameter != None :
        if menu.options.skip_parameter.startswith("="):
          menu.options.skip_parameter = menu.options.skip_parameter[1:]
        settings.TEST_PARAMETER = menu.options.skip_parameter.split(settings.PARAMETER_SPLITTING_REGEX)

      for i in range(0,len(settings.TEST_PARAMETER)):
        if "=" in settings.TEST_PARAMETER[i]:
          settings.TEST_PARAMETER[i] = settings.TEST_PARAMETER[i].split("=")[0]
          
    # Check injection level, due to the provided testable parameters.
    if menu.options.level < 2 and menu.options.test_parameter != None:
      checks.check_injection_level()

    # Check if defined character used for splitting cookie values.
    if menu.options.cdel:
     settings.COOKIE_DELIMITER = menu.options.cdel

    # Check for skipping injection techniques.
    if menu.options.skip_tech:
      if menu.options.tech:
        err_msg = "The options '--technique' and '--skip-technique' cannot be used "
        err_msg += "simultaneously (i.e. only one option must be set)."
        print settings.print_critical_msg(err_msg)
        raise SystemExit

      settings.SKIP_TECHNIQUES = True
      menu.options.tech = menu.options.skip_tech

    # Check if specified wrong injection technique
    if menu.options.tech and menu.options.tech not in settings.AVAILABLE_TECHNIQUES:
      found_tech = False

      # Convert injection technique(s) to lowercase
      menu.options.tech = menu.options.tech.lower()

      # Check if used the ',' separator
      if settings.PARAMETER_SPLITTING_REGEX in menu.options.tech:
        split_techniques_names = menu.options.tech.split(settings.PARAMETER_SPLITTING_REGEX)
      else:
        split_techniques_names = menu.options.tech.split()
      if split_techniques_names:
        for i in range(0,len(split_techniques_names)):
          if len(menu.options.tech) <= 4:
            split_first_letter = list(menu.options.tech)
            for j in range(0,len(split_first_letter)):
              if split_first_letter[j] in settings.AVAILABLE_TECHNIQUES:
                found_tech = True
              else:  
                found_tech = False  
                          
      if split_techniques_names[i].replace(' ', '') not in settings.AVAILABLE_TECHNIQUES and \
         found_tech == False:
        err_msg = "You specified wrong value '" + split_techniques_names[i] 
        err_msg += "' as injection technique. "
        err_msg += "The value for '"
        if not settings.SKIP_TECHNIQUES :
          err_msg += "--technique"
        else:
          err_msg += "--skip-technique"
          
        err_msg += "' must be a string composed by the letters C, E, T, F. "
        err_msg += "Refer to the official wiki for details."
        print settings.print_critical_msg(err_msg)
        raise SystemExit()

    # Check if specified wrong alternative shell
    if menu.options.alter_shell:
      if menu.options.alter_shell.lower() not in settings.AVAILABLE_SHELLS:
        err_msg = "'" + menu.options.alter_shell + "' shell is not supported!"
        print settings.print_critical_msg(err_msg)
        raise SystemExit()

    # Check the file-destination
    if menu.options.file_write and not menu.options.file_dest or \
    menu.options.file_upload  and not menu.options.file_dest:
      err_msg = "Host's absolute filepath to write and/or upload, must be specified (i.e. '--file-dest')."
      print settings.print_critical_msg(err_msg)
      raise SystemExit()

    if menu.options.file_dest and menu.options.file_write == None and menu.options.file_upload == None:
      err_msg = "You must enter the '--file-write' or '--file-upload' parameter."
      print settings.print_critical_msg(err_msg)
      raise SystemExit()
  
    # Check if defined "--url" or "-m" option.
    if url:
      if menu.options.auth_cred and menu.options.auth_cred and settings.VERBOSITY_LEVEL >= 1:
        success_msg = "Used a valid pair of " + menu.options.auth_type 
        success_msg += " HTTP authentication credentials '" + menu.options.auth_cred + "'." 
        print settings.print_success_msg(success_msg)
      # Load the crawler
      if menu.options.crawldepth > 0 or menu.options.sitemap_url:  
        url = crawler.crawler(url)
      try:
        if menu.options.flush_session:
          session_handler.flush(url)
        # Check for CGI scripts on url
        checks.check_CGI_scripts(url)
        # Modification on payload
        if not menu.options.shellshock:
          if not settings.USE_BACKTICKS:
            settings.SYS_USERS  = "echo $(" + settings.SYS_USERS + ")"
            settings.SYS_PASSES  = "echo $(" + settings.SYS_PASSES + ")"
        # Check if defined "--file-upload" option.
        if menu.options.file_upload:
          checks.file_upload()
          try:
            urllib2.urlopen(menu.options.file_upload)
          except urllib2.HTTPError, err_msg:
            print settings.print_critical_msg(str(err_msg.code))
            raise SystemExit()
          except urllib2.URLError, err_msg:
            print settings.print_critical_msg(str(err_msg.args[0]).split("] ")[1] + ".")
            raise SystemExit()
        try:
          # Webpage encoding detection.
          requests.encoding_detection(response)
          if response.info()['server'] :
            server_banner = response.info()['server']
            # Procedure for target server's operating system identification.
            requests.check_target_os(server_banner)
            # Procedure for target server identification.
            requests.server_identification(server_banner)
            # Procedure for target application identification
            requests.application_identification(server_banner, url)
            # Store the Server's root dir
            settings.DEFAULT_WEB_ROOT = settings.WEB_ROOT
            if menu.options.is_admin or menu.options.is_root and not menu.options.current_user:
              menu.options.current_user = True
            # Define Python working directory.
            checks.define_py_working_dir()
            # Check for wrong flags.
            checks.check_wrong_flags() 
          else:
            found_os_server = checks.user_defined_os()
        except KeyError:
          pass
        # Load tamper scripts
        if menu.options.tamper:
          checks.tamper_scripts()