Ok so this is my first post on StackOverflow, so go easy on me. I'm literally stuck with my Python script. I looked all over the web, cannot find a solution!
So I used mechanize to login to a website (example: http://www.foobar.com/)
HTML of form to login:
form id="loginForm" method="post" action="/z/0.123/?cmd=login-post" onsubmit="return someSubmitfunction();"
The form for the login of that website looks like this:
<HiddenControl(__FOO=someLongString) (readonly)>
<TextControl(emailAddress=)>
<PasswordControl(password=)>
<CheckboxControl(persist=[*on])>
I WAS able to login to the website and redirect to an internal link (see further in code).
Here is the code for the login... Note: Request Method is a POST
import urllib, urllib2
import cookielib
import mechanize
# Note this is the FORM, but missing the HIDDEN value, LOOK lower in code
EmailAddress = 'someusername'
Password = 'somepassword'
Persist = ['on',]
browser = mechanize.Browser()
# Enable cookie support
cookiejar = cookielib.LWPCookieJar()
browser.set_cookiejar( cookiejar )
# Browser options
browser.set_handle_equiv( True )
browser.set_handle_redirect( True )
browser.set_handle_referer( True )
browser.set_handle_robots( False )
# Pretend that I am a browser
browser.set_handle_refresh( mechanize._http.HTTPRefreshProcessor(), max_time = 1 )
browser.addheaders = [ ( 'User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1' ) ]
# Open webpage & add form fields
browser.open('http://www.foobar.com/')
browser.select_form(nr = 0) #select the ONLY form (Login form)
browser.form['emailAddress'] = EmailAddress
browser.form['password'] = Password
browser.form['persist'] = Persist
# Submit for FORM is an action, find it and redirect to internal page
# Create new control & submit to internal page
browser.new_control("HIDDEN", "action", {})
control = browser.form.find_control("action")
control.readonly = False
browser["action"] = "/z/0.123/?cmd=login-post"
browser.method = "post"
browser.action = 'http://www.foobar.com/user/summary/'
browser.submit()
Alrighty, up to this point, I am fine. I SUCCESSFULLY logged in and was redirected to http://www.foobar.com/user/summary/ just like I wanted.
url = browser.open('http://www.foobar.com/user/summary/')
print url.read() # - see content of url HTML ### THIS WORKS ###
Now I use BeautifulSoup() to parse the HTML of /user/summary/ and successfully grab another form on this page. This form doesn't have an action, like the login form, but this is how it looks...
I NEED HELP FROM HERE down.. I have trouble inputting my text(myInput) into the form and submitting!
HTML of form from .../user/summary/:
form method="post" id="foobar" name="foobar">
This is the submit button for the form:
onkeypress="return submitFormKey(event, '','foobar', 'foobar', 'pcm');">
img src="someuglyimage.jpg" class="submit" id="btn_Submit" onclick="submitForm('foobar', 'foobar', 'pcm');" alt="Foo"
This is the actual form: (THE ONLY FORM on this page, once again!)
<HiddenControl(hdnCmd=foobar) (readonly)>
<TextControl(inputvalue=)>
I tried many methods of submitting. I tried using Selenium, Splinter, urlib(1 & 2), and even JSON, javascript, iframe, embed, etc. I'M STUCK, HELP PLZ!
I thought this will work, i tried with and without Hidden control:
browser.select_form(nr = 0) #select the 1st form for inputting value
browser.form['inputvalue'] = myInput #MY INPUT I WANT THERE
browser.new_control("hidden", "foobar", {})
control = browser.form.find_control("foobar")
control.readonly = False
#browser["foobar"] = "/?cmd=foobar&from=/user/summary"
browser.method = "post"
response = browser.submit()
print response.read()
MY RESULTS:
Apparently It seems to redirect me to the homepage of the website (302 Redirect). So I KNOW that most likely it's something to do with the hidden value and passing it to the javascript/Ajax call (onclick="submitForm) when I submit. I read about CSRF tokens and it could be that, but if anyone has any ideas on how to do this, let me know because I'm in desperate need of help.
And somehow I cannot find the form of .../user/summary/ (console tells me this) because I am redirected to the homepage, even though I dont submit the browser, until after I input all the form fields...
I can read the HTML of .../user/summary/ and find the "foobar" form! This is why I am so confused. I can read it, parse it, but when i try to input myInput into the form, somehow I get redirected to homepage, but I am still logged in!
THANKS pplz.. hopefully I was clear!
Related
All:
I have an issue with a project I am working on using C# MVC4
In the project, I am accepting a URL and other parameters from a user, then do some processing and send the result of the processing to the URL provided by the user.
The result is being sent using the following code:
var context = HttpContext.Current;
context.Response.Write("<html><head>");
context.Response.Write("</head><body>");
context.Response.Write(string.Format("<form name=\"myform\" method=\"post\" action=\"{0}\" >", postUrl));
context.Response.Write("</form>");
context.Response.Write("<script type=\"text/javascript\">document.myform.submit();</script></body></html>");
context.Response.Write("</body>");
context.Response.Flush();
context.Response.Clear();
context.ApplicationInstance.CompleteRequest();
Whenever a user attempts an XSS like passing a url value of javascript%3aalert('xss')%2f%2f, the JavaScript runs and the pop up shows up.
I've tried Antixss.HtmlEncode() to encode the URL before passing it into string.Format but still doesn't work. I've tried Antixss.UrlEncode() also, but this gives error as the form doesn't submit to the URL.
Please help me out, Is there something I am missing? What else can I do?
Thanks in advance.
You will need a three pronged approach to solve this issue.
Preventing XSS injection:
Note that if a user injected the url value
" /> <script>alert('xss')</script>
this would also leave you vulnerable:
<form name="myform" method="post" action="" /> <script>alert('xss')</script>" >
Therefore you should use the HttpUtility.HtmlAttributeEncode function to solve this one.
However, don't stop there. As noted, you should project against javascript: style URLs. For this I would ensure that the URL begins with http:// or https://. If not, throw a SecurityException which you should be logging and handling server-side, and showing the user a custom error page.
Finally, you want to protect against Open Redirect Vulnerabilities. This is to stop phishing attacks by redirecting users to other domains. Again, use a whitelist approach and ensure that the domain redirected to is one of your own. Be careful on the parsing here, as it is easy to get it wrong - a URL of http://example.org?http://example.com will pass the validation filter for example.com on many badly written validation routines. I recommend using the Uri object in .NET and retrieving the domain through that rather than rolling your own string functions.
You could also check if the URL is a relative URL, and allow it if acceptable. Use something like this function which uses a built in .NET library to ensure that it is relative or not.
Just a thought - try putting this script in rather than just document.myform.submit (and remove the form's action property):
if("{0}".indexOf('http') !== 0) {
//this is some sort of injection, or it's pointing at something on your server. Should cover http and https.
//Specifically, it makes sure that the url starts with 'http' - so a 'javascript' url isn't going to work.
} else {
document.myform.action="{0}"
document.myform.submit();
}
There is more you could do, but this should help.
Since you are adding the postUrl as an attribute "action" of the form tag, you can try using HtmlAttributeEncode method in the HttpUtility
[ValidateInput(false)]
public ActionResult Test(string url)
{
var context = System.Web.HttpContext.Current;
context.Response.Write("<html><head>");
context.Response.Write("</head><body>");
context.Response.Write(string.Format("<form name=\"myform\" method=\"post\" action=\"{0}\" >", HttpUtility.HtmlAttributeEncode(url)));
context.Response.Write("</form>");
context.Response.Write("<script type=\"text/javascript\">document.myform.submit();</script></body></html>");
context.Response.Write("</body>");
context.Response.Flush();
context.Response.Clear();
context.ApplicationInstance.CompleteRequest();
return null;
}
http://localhost:39200/home/test?url=https%3A%2F%2Fwww.google.com - Worked
http://localhost:39200/home/test?url=%3Cscript%3Ealert(%27test%27)%3C%2Fscript%3E - Worked(Did not show alert)
It is always good practice to Validate the user input against a white list of inputs, to prevent XSS exploits.
try using HttpUtility.UrlEncode
something like Response.Write(HttpUtility.UrlEncode(urlString));
see How To: Prevent Cross-Site Scripting in ASP.NET for more steps =)
I'm using Python 3.3 and Requests 2.2.1.
I'm trying to POST to a website ending in .jsp, which then changes to .doh ending. Using the same basic requests code outline I'm able to successfully login and scrape other websites, but the javascript part on this site is not working. This is my code:
import requests
url = 'https://prodpci.etimspayments.com/pbw/include/sanfrancisco/input.jsp'
payload = {'plateNumber':'notshown', 'statePlate':'CA'} #tried CA and California
s = requests.Session() #Tried 'session' and 'Session' following different advice
post = s.post(url, data=payload)
r = s.get('https://prodpci.etimspayments.com/pbw/include/sanfrancisco/input.jsp')
print(r.text)
Finally, when manually entering data into the webpage through firefox browser, the page changes and url becomes https://prodpci.etimspayments.com/pbw/inputAction.doh, which only has contet if you are redirected there after typing in license plate.
From the printed text, I know I'm getting content from the page as it would be without POSTing anything, but I need the content for the page once I've POSTed the payload.
For the POST payload, do I need to include something like 'submit':'submit' to simulate clicking the search button?
Am I doing the GET request from the right url, considering the url I POST to?
You're making POST request and after that another GET request and this is why you get the same page with the form.
response = s.post(url, data=payload)
print(response.text)
Also if you check the form markup, you'll find its action is /pbw/inputAction.doh and additionally the form sends a few parameters from hidden inputs. Therefore you should use that URL in your request and probably the values from hidden inputs.
With the next code I'm able to retrieve the same response as via regular request in browser:
import requests
url = 'https://prodpci.etimspayments.com/pbw/inputAction.doh'
payload = {
'plateNumber': 'notshown',
'statePlate': 'CA',
'requestType': 'submit',
'clientcode': 19,
'requestCount': 1,
'clientAccount': 5,
}
s = requests.Session()
response = s.post(url, data=payload)
print(response.text)
The same you can see in browser after same request via the form:
...
<td colspan="2"> <li class="error">Plate is not found</li></td>
...
Ok, so in my rails app on one of the pages I needed to pass a Javascript variable so that it was available to rails. Now one runs server side and one runs client side so I know this is very difficult. I looked to the internet and found a solution that involved dynamically creating a form in a function included in my external javascript page.
Basically, a form with a hidden field was made using document.createElement statements and the hidden field was given the value of what I wanted to pass to rails and then form.submit() is called so that the form is submitted. the form was given a method of post and it was given a path to go to. So when submit it called the page redirects to another page with the hidden field now in the params hash and accessible by rails with params[:param].
This worked great for a while, until we started using session to keep track of a logged in user. After clicking the button to be redirected with that dynamic form the session gets cleared. The only thing I found online about sessions being cleared is when rails detects a CSRF it clears the session.
So could what I'm doing cause rails to detect a CSRF and thus clear my session? is there any other reason the session might be cleared that anybody knows of? Also, without ajax (because I'm just not up to screwing with that, it doesnt play nicely.) is there another good way im missing to pass a javascript variable (it has to be javascript, I'm using a javascript function to get the users current location) so that it is available to rails? (I'm thinking rather than javascripting the form, I might just make a hidden form right on my page, although this is a little less elegant because anybody looking at the source can see it and wonder why its there and screw with it)
if anybody is interested, below is the code for my dynamic form function.
function post_to_url(path, params, method) {
method = method || "post"; // Set method to post by default, if not specified.
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path); //page to go redirect to when form submitted
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
//after form is submitted params is available by params[:location]
hiddenField.setAttribute("name", 'location');
hiddenField.setAttribute("value", params )
form.appendChild(hiddenField);
document.body.appendChild(form);
form.submit();
}
In any form requests, and ajax the CSRF token must be passed through. You need to create a hidden field in the form with the name authenticity_token. Then you need to grab the value from the meta tag:
<meta content="some_token_value" name="csrf-token" />
Like so:
var token = "";
var tags = document.getElementsByTagName("meta");
for(var i = 0; i < tags.length; i++) {
if(tags[i].name == "csrf-param") {
token = tags[i].content;
}
}
Then simply drop that in the value of the hidden tag, much like you did for the location value.
you can add an erb line in your javascript file:
var csrf_token = '<%= form_authenticity_token %>';
then in your requests, add 'authenticity_token' : csrf_token in the post-data.
I'm using jQuery with Django in server-side. What I'm trying to do is to get some text from the user through the form and simultaneously displaying the text in the canvas area like about.me and flavors.me does. Then the user drag the text in the canvas area to the desired position and when they click the next button,the data must be stored in the database and redirect to the homepage. Everything is working perfect(the datas are stored in the database) except when I click the button which I set window.location to "http://127.0.0.1:8000". But I'm not getting to that page when I click the button.
I'm getting some errors in Django server:
error: [Errno 32] Broken pipe
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 51161)
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 284, in _handle_request_noblock
Here is my html:
https://gist.github.com/2359541
Django views.py:
from cover.models import CoverModel
from django.http import HttpResponseRedirect
def coverview(request):
if request.is_ajax():
t = request.POST.get('top')
l = request.POST.get('left')
n = request.POST.get('name')
h = request.POST.get('headline')
try:
g = CoverModel.objects.get(user=request.user)
except CoverModel.DoesNotExist:
co = CoverModel(top=t, left=l, name=n, headline=h)
co.user = request.user
co.save()
else:
g.top = t
g.left = l
g.name = n
g.headline = h
g.save()
return HttpResponseRedirect("/")
urls.py:
url(r'^cover/check/$', 'cover.views.coverview'),
url(r'^cover/$', login_required(direct_to_template), {'template': 'cover.html'}),
Could anyone help me?
Thanks!
There's really not enough information in your question to properly diagnose this, but you can try this:
It's always a bad idea to hard-code a domain name in your JS. What happens when you take this to production, for example? If you want to send the user to the homepage (presumed from the location being set to http://127.0.0.1:8000/), then set the location simply to /. That will ensure that it will always go to the site root regardless of the IP address, domain name or port.
Part of the problem is that you're trying to post data, and then immediately leaving the page by using window.location. You should only change the window.location whenever you get the response back from the $.post().
$.post("check/", { top: t, left: l, name: n, headline: h}, function(data) {
window.location.href = "/";
});
Notice also that I removed the hardcoded URL. Use a relative one here, like Chris said.
If it still isn't working, you need to check for Javascript errors in the lines above. Use Firebug, Chrome Dev Tools, Opera Dragonfly, something. Check to make sure your POST is actually going through, and post more data about that back here.
I am using jQuery (latest) and have a entirely ajax through post login form. The form is monitored by this code:
$("form").live("submit", function(event) {
event.preventDefault();
var input = {};
input.url = $(this).attr('action');
input.data = $(this).serializeArray();
var output = Site.getResponse(input);
if(output.success) {
params = {};
params.title = 'Dashboard';
params.url = '/user/dashboard';
Page.instance().load(params);
}
});
So, essentially the browser should still recognize the post because it happens from the form's submit, I just use jQuery to stop that submit so I can process it. Is there a way to "trick" modern browsers into saving the password for my site without iframes, please.
IMHO the best way to handle login is to add this line to the end of the login script
header("Location: " . $_SERVER['HTTP_REFERER']);
or some constant url, depending on what you want. This way the page doesn't change and the form submits, therefore the browser remember's the password.