I am doing a CTF challenge, but my question is not about how to solve it, rather the syntax. The challenge is to read the secret key in Flask server's configuration. It is stored in the app.secret_key variable and I want to alert it on the screen by XSS.
Question: how can I access that variable in Flask code from javascript and put it in <script>alert(variable)</script> snippet?
I tried <script type="text/javascript">let v="{{=app.secret_key}}"; alert(v); </script> but it gave Internal Server Error.
First, it must be said, in general you should should absolutely not do this. app.secret_key should never, ever be exposed publicly and should be regarded as a closely guarded secret. Hence the name. But since you're doing this for presumably good reasons involving your game, let's continue.
Probably the simplest way to expose Python variables to JavaScript is directly in the template by dumping JSON. Consider this code:
import json
from flask import Flask, render_template
app = Flask(__name__)
app.secret_key = 'THIS IS SECRET'
#app.route('/')
def hello_world():
server_vars = {
'secretKey': app.secret_key,
'favoriteFoods': ['Eggs', 'Spam']
}
return render_template(
'hello.html',
server_vars=json.dumps(server_vars)
)
if __name__ == '__main__':
app.run()
We're rendering the template hello.html and sending it a template variable, server_vars, which is a rendered JSON string of the same server-side variable, which is a dictionary. This enables us to send any number arbitrary JSON-compatible variables to JavaScript. See hello.html:
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
window.serverVars = {{ server_vars | safe }};
alert(window.serverVars.secretKey)
console.log('btw, my favorite foods are', window.serverVars.favoriteFoods)
</script>
</body>
</html>
Notice that in addition to sending secretKey, we actually sent a Python list, which was converted into an array in JavaScript.
Related
I want to make a variable with Python, and then console.log() the variable in JavaScript. I know how to access the variable in JavaScript, but I don't know how to make the Python script run when the page is loaded. How can I do this?
Unlike Javascript, you can't run Python directly in the browser. You would need Python to run server-side. A possible alternative may be to use transcrypt to generate javascript equivalents of Python for a frontend-only solution.
For instance, transcrypt allows you to "import" python modules into JavaScript. Here, a python script called hello.py is "imported" into the context and can be called form javascript like hello.solarSystem.greet()
<script type="module">import * as hello from './__target__/hello.js'; window.hello = hello;</script>
<h2>Hello demo</h2>
<p>
<div id = "greet">...</div>
<button onclick="hello.solarSystem.greet ()">Click me repeatedly!</button>
<p>
<div id = "explain">...</div>
<button onclick="hello.solarSystem.explain ()">And click me repeatedly too!</button>
See the transcrypt docs for more info.
Otherwise, you'd probably be running a Python webserver on the backend for this use-case. Something like flask.
from flask import Flask, render_template_string
app = Flask(__name__)
def do_something():
"""Returns an interesting value"""
return "foo"
template = """
<html>
<script>
console.log('{{ value }}')
</script>
"""
#app.route('/')
def home():
my_value = do_something()
return render_template_string(template, value=my_value)
app.run(debug=True)
I'm at a beginner at coding and i'm stuck at the final closing :|
i'm using python 2.7
this is my serever.py
from flask import Flask, render_template,request,jsonify
import requests
import json
import new
app = Flask(__name__)
#serve homepage
#app.route('/', methods=["GET","POST"])
def homepage():
return render_template('page2.html')
#app.route('/page3.html', methods=["POST"])
def result_matchup():
h= request.form['h']
a= request.form['a']
l= request.form['l']
p= request.form['p']
result = json.dumps(new.calc(h,a,l,p))
return render_template('page3.html',result=result)
if __name__ == "__main__":
app.run(debug=True)
when i ask for return result for checking myself, this is the output:
{"f": 197.1, "k": 196}
this is my page3.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<center><h1>Final = {{f}}</h1></center>
</body>
</html>
the output for all this is
"Final = "
,while I expect for Final = 197.1.
what am I doing wrong? any help?
thanks!
I assume new.calc returns a dictionary. No need to use json.dumps to stringify that before passing to your template. So instead try:
result = new.calc(h,a,l,p)
result should now be a dictionary, with the keys 'f' and 'k'
Therefor in the template you should access this dictionary, as you would in python:
<center><h1>Final = {{result['f']}}</h1></center>
I would also advise using a later version of python since 2.7 is unsupported now, and making this change early will prevent you having to make already written code, 3.x compatible later.
Two suggestions:
You serialize your result as JSON writing result = json.dumps(new.calc(h,a,l,p)). However, you should directly pass a Python object to render_template. In fact, that's one of the strengths of Jinja templating: You do not need to pass JSON, but you can handle Python objects directly. So just write result = new.calc(h,a,l,p).
Second, within the Jinja template, you have to access the objects as you passed them through your render_template function. In your case, <center><h1>Final = {{result['f]}}</h1></center> should do the job.
How do I retrieve data fro this Python Server in Javacript. The end goal is to be able to use Python variables to Control Javascript variables. I've scoured everywhere for hints on how to work with sockets and javascript but they only dive into sending data whereas I'm wanting to receive data.
Thanks in Advance! :)
Python Server Code:
import socket
UDP_IP = socket.gethostname()
UDP_PORT = 5005
ip_address = socket.gethostbyname(socket.gethostname())
MESSAGE = "Hello, World!"
print ("UDP target IP:", UDP_IP)
print("IP Address is",ip_address)
print ("UDP target port:", UDP_PORT)
print ("message:", MESSAGE)
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
#sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
sock.sendto(bytes(MESSAGE, "utf-8"), (ip_address, UDP_PORT))
JAVASCRIPT CLIENT:
var socket = io.connect('http://127.0.0.1:5005');
Best option should be flask
#app.route('/')
def hello():
data = {'username': 'Pang', 'site': 'stackoverflow.com'}
return render_template('settings.html', data=data)
In the above code you specify the route and the data you want to send, previously processed in a python variable.
In your js:
function myFunc(vars) {
return vars
}
In this way you should be able to view your values and use them
In your html
<html>
<head>
<script type="text/javascript" {{ url_for('static', filename='app.js')}}></script>
<script type="text/javascript">
myVar = myFunc({{vars|tojsenter code hereon}})
</script>
</head>
In the above code you store your data reciebed in MyVar, you can omit the json parsing.
I created a website with HTML/CSS. I also used Javascript for events (click on button, ...).
Now I want to connect a Python script with it and more importantly, return the results from my Python functions to my website and display (use) them there.
Consider something like this: I have a website with an input field and a button. If you click on the button, a Python script should run which returns if the input is an odd or even number (of course you don't need Python for this specific case, but that's what I want to do).
From my research I believe Flask is the library to be used for this, but I really don't know how to do it. I found very few examples. I would really appreciate if someone could implement the above example or tell me how to do it exactly.
I know there are already some questions about that concept here online, but as I said, with very few examples.
You're right about Flask being a good solution for this and there are examples and tutorials everywhere. If what you want is just to run a specific function on a button press and get something back in javascript, I've put a quick example is below.
# app.py
from flask import Flask, render_template
from flask import jsonify
app = Flask(__name__)
# Display your index page
#app.route("/")
def index():
return render_template('index.html')
# A function to add two numbers
#app.route("/add")
def add():
a = request.args.get('a')
b = request.args.get('b')
return jsonify({"result": a+b})
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
This can then be run with python app.py and make sure your index.html is in the same directory. Then you should be able to go to http://127.0.0.1/ and see your page load.
This implements a function which adds two numbers, this can be called in your javascript by calling http://127.0.0.1/add?a=10&b=20. This should then return {"result": 30}.
You can grab this in your javascript using the code below and place this code in your buttons on click callback.
let first = 10;
let second = 20;
fetch('http://127.0.0.1/add?a='+first+'&b='+second)
.then((response) => {
return response.json();
})
.then((myJson) => {
console.log("When I add "+first+" and "+second+" I get: " + myJson.result);
});
This should be the barebone basics, but once you can submit data to Flask and get data back, you now have an interface to run things in Python.
Edit: Full Front-end example
https://jsfiddle.net/4bv805L6/
I really appreciate time spent on this answer. But the answer did not help me in the way I needed it. At that point I had no clue what to do, but since thenbI figured it out some time ago and I thought I should share my solution here:
That's app.py:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/stick', methods=['GET', 'POST'])
def stick():
if request.method == 'POST':
result = request.form['string1'] + request.form['string2']
return render_template('index.html', result=result)
else:
return render_template('index.html')
if __name__ == "__main__":
app.run()
And that's index.html (put in the folder templates):
<!DOCTYPE html>
<html>
<body>
<h3> Stick two strings </h3>
<form action="{{ url_for('stick') }}" method="post">
<input type="text" name="string1">
<input type="text" name="string2">
<input type="submit" value="Go!">
<p id="result"></p>
</form>
<script>
document.getElementById("result").innerHTML = "{{result}}"
</script>
</body>
</html>
In the terminal, type in python app.py and it should work.
So I have a simple Django script which I've found online for an AJAX function that runs a Python script and gets the output via stdout.
views.py
from django.shortcuts import render
def index(request):
return render(request,'homepage/page.html')
homepage/page.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
$(function()
{
$('#clickme').click(function(){
alert('Im going to start processing');
$.ajax({
url: "static/homepage/js/external_func.py",
type: "POST",
datatype:"json",
data: {'key':'value','key2':'value2'},
success: function(response){
console.log(response.keys);
console.log(response.message);
}
});
});
});
</script>
</head>
<body>
<button id="clickme"> click me </button>
</body>
</html>
So you can see my url is linked to external_func.py which runs after the button is clicked. The script then returns a json.
external_func.py
import sys
import json
import cgi
fs = cgi.FieldStorage()
sys.stdout.write("Content-Type: application/json")
sys.stdout.write("\n")
sys.stdout.write("\n")
result = {}
result['success'] = True
result['message'] = "The command Completed Successfully"
result['keys'] = ",".join(fs.keys())
d = {}
for k in fs.keys():
d[k] = fs.getvalue(k)
result['data'] = d
sys.stdout.write(json.dumps(result, indent=1))
sys.stdout.write("\n")
sys.stdout.close()
However, when I run the server and clicked on the button, the console shows undefined for both values, meaning response.keys and response.message is undefined.
Now, when I instead switch the code to console.log(response) in homepage/page.html. The console prints out the entire external_func.py code in text.
I couldn't find a solution online. It seems like people rarely calls a Python script in an AJAX request, I see a lot of forum posts about AJAX calling for a php code instead.
EDIT1:
I have to clarify one thing. This is just a small section of my project which I want to run some test on. In my actual project, I will have a function in python that takes a long time to compute, hence I prefer to have a webpage partially rendered with a waiting icon while the function processes. The output from the function will then be displayed on a webpage.
You have a django app, and yet you are using CGI for this function? Why? Why not simply make the function another django view? Serving your response with django is much superior to CGI, unless that function significantly bloats or slows down your django. It is as easy as this:
from django.http import JsonResponse
def func(request):
result = ...
return JsonResponse(result)
If you really want to separate this into a CGI script, the most likely reason you are failing to get a response is your web server not being configured to process the CGI request. (Your Developer Tools Network tab is a great help for diagnosing exactly what kind of response you got.) For security reasons CGI is not enabled by default. You need to tell Apache (or whatever web server you are using) that CGI should be enabled for that directory, and that it should be associated with .py files.