[TOC]
web/LexMACS’ Secret F12一下,发现以下文本:
1 <div><div><div><div>L<div><div><div><div>I<div><div><div><div>T<div><div><div><div>C<div><div><div><div>T<div><div><div><div>F<div><div><div><div>{<div><div><div><div>S<div><div><div><div>e<div><div><div><div>C<div><div><div><div>R<div><div><div><div>3<div><div><div><div>t<div><div><div><div>_<div><div><div><div>h<div><div><div><div>A<div><div><div><div>s<div><div><div><div>-<div><div><div><div>B<div><div><div><div>3<div><div><div><div>e<div><div><div><div>n<div><div><div><div>-<div><div><div><div>l<div><div><div><div>E<div><div><div><div>4<div><div><div><div>K<div><div><div><div>d<div><div><div><div>}</div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></body>
去除div标签即可得到flag:LITCTF{SeCR3t_hAs-B3en-lE4Kd}
web/file viewer app.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from flask import Flask, request, send_file, abort, render_template_stringimport osapp = Flask(__name__) HTML_TEMPLATE = """ <!DOCTYPE html> <html> <head> <title>My File View</title> </head> <body> <h1>Welcome to my file viewer!</h1> <p>Click on the button below to view a random sample file.</p> <button onclick="window.location.href='/view-file?file=' + getRandomFile()">View Random File</button> <script> function getRandomFile() { const files = ["sample1.txt", "sample2.txt", "sample3.txt"]; return files[Math.floor(Math.random() * files.length)]; } </script> </body> </html> """ @app.route('/' ) def index (): return render_template_string(HTML_TEMPLATE) @app.route('/view-file' ) def view_file (): filename = request.args.get('file' , '' ) filepath = os.path.join('files' , filename) if not os.path.exists(filepath): return abort(404 ) return send_file(filepath) if __name__ == '__main__' : app.run(host='0.0.0.0' , port=5000 )
一眼,有目录穿越。 但尝试读取有用的文件,都没有什么信息。Linux文件知识+1:/proc/self/cwd符号链接指向当前进程的工作目录
通过这个目录以及对flag文件名猜测最终得到flag:LITCTF{o0ps_f0rg0t_t0_s3cur3_my_dir3ct0ry}
web/file viewer 2 app.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 from flask import Flask, request, send_file, abort, render_template_stringimport osapp = Flask(__name__) HTML_TEMPLATE = """ <!DOCTYPE html> <html> <head> <title>My File View</title> </head> <body> <h1>Welcome to my file viewer!</h1> <p>Click on the button below to view a random sample file. Also, you can't look at my secrets anymore -- I secured that directory this time around ;)</p> <button onclick="window.location.href='/view-file?file=' + getRandomFile()">View Random File</button> <script> function getRandomFile() { const files = ["sample1.txt", "sample2.txt", "sample3.txt"]; return files[Math.floor(Math.random() * files.length)]; } </script> <p>Oh also -- here are some pictures from my most recent vacation. Take a look at these, since you can't look at my secrets now anyway :)</p> <img src="/view-file?file=images/sailboat.jpg" width="200" height="auto"> <img src="/view-file?file=images/seagulls.jpg" width="200" height="auto"> <img src="/view-file?file=images/sunset.jpg" width="200" height="auto"> <img src="/view-file?file=images/beach.jpg" width="200" height="auto"> </body> </html> """ @app.route('/' ) def index (): return render_template_string(HTML_TEMPLATE) @app.route('/view-file' ) def view_file (): filename = request.args.get('file' , '' ) if filename[0 :2 ] == '..' : return abort(400 , "Stop trying to look at my secrets >:(" ) filepath = os.path.join('files' , filename) print (filepath) if not os.path.exists(filepath) or not os.path.isfile(filepath): return abort(404 ) return send_file(filepath) if __name__ == '__main__' : app.run(host='0.0.0.0' , port=5000 )
题目描述说他把什么目录加密了,但同样的打法出了,没懂它加密了什么。可能是非预期了。
web/tabled 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 from flask import Flask, request, redirect, url_for, render_template_string, sessionimport sqlite3import randomimport stringimport osapp = Flask(__name__) app.secret_key = os.urandom(24 ) flag = "LITCTF{[redacted]}" def init_db (): conn = sqlite3.connect("users.db" ) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL )''' ) characters = string.ascii_letters + string.digits randomstring = 'a' + '' .join(random.choice(characters) for _ in range (100 )) c.execute("CREATE TABLE IF NOT EXISTS " + randomstring + " (flag TEXT)" ) c.execute("INSERT INTO " + randomstring + " (flag) VALUES ('" + flag + "')" ) conn.commit() conn.close() init_db() login_page = """ <!doctype html> <title>Login</title> <h2>Login</h2> <form method="post"> Username: <input type="text" name="username"><br><br> Password: <input type="password" name="password"><br><br> <input type="submit" value="Login"> </form> <p>Don't have an account? <a href="{{ url_for('register') }}">Register here</a></p> {% if error %} <p style="color:red">{{ error }}</p> {% endif %} """ register_page = """ <!doctype html> <title>Register</title> <h2>Register</h2> <form method="post"> Username: <input type="text" name="username"><br><br> Password: <input type="password" name="password"><br><br> <input type="submit" value="Register"> </form> <p>Already have an account? <a href="{{ url_for('login') }}">Login here</a></p> {% if error %} <p style="color:red">{{ error }}</p> {% endif %} """ home_page = """ <!doctype html> <title>Home</title> <h2>Welcome, {{ user }}!</h2> <a href="{{ url_for('logout') }}">Logout</a> """ @app.route("/" , methods=["GET" , "POST" ] ) def login (): error = None if request.method == "POST" : username = request.form["username" ] password = request.form["password" ] conn = sqlite3.connect("users.db" ) c = conn.cursor() c.execute("SELECT username FROM users WHERE username='" + username + "' AND password='" + password + "'" ) user = c.fetchone() conn.close() if user: session["username" ] = user[0 ] return redirect(url_for("home" )) else : error = "Invalid username or password" return render_template_string(login_page, error=error) @app.route("/register" , methods=["GET" , "POST" ] ) def register (): error = None if request.method == "POST" : username = request.form["username" ] password = request.form["password" ] if not username or not password: error = "Both fields are required" else : try : conn = sqlite3.connect("users.db" ) c = conn.cursor() c.execute("INSERT INTO users (username, password) VALUES ('" + username + "', '" + password + "')" ) conn.commit() conn.close() return redirect(url_for("login" )) except sqlite3.IntegrityError: error = "Username already exists" return render_template_string(register_page, error=error) @app.route("/home" ) def home (): if "username" in session: return render_template_string(home_page, user=session["username" ]) return redirect(url_for("login" )) @app.route("/logout" ) def logout (): session.pop("username" , None ) return redirect(url_for("login" )) if __name__ == "__main__" : app.run(debug=True )
一个简单的登录框,源码中有sql语句,推测是sql注入,sqlmap一把梭: