문제 설명

you need login with "admin"s id!

===========================
create table tmitter_user(
    idx int auto_increment primary key,
    id char(32),
    ps char(32)
);


풀이

문제 설명을 읽어보면 admin의 id로 로그인해야 한다고 되어있다. 접속해보면 tmitter은 twitter의 가짜가 아니라고 한다.

image-20240204163406334


Sign Up 버튼을 누르면 아래와 같은 join.php가 나오고 소스 코드를 분석해보았다.

image-20240204163748586


join.php의 소스코드는 아래와 같고 POST 메소드로 idps를 입력받고 chk() 함수를 실행한다. 이 함수는 id의 길이는 4보다 크고, ps의 길이는 7보다 커야 한다.

<script>
  function chk(f){
   if(f.id.value.length<4){alert("chk id"); return false;}
   if(f.ps.value.length<7){alert("chk ps"); return false;}
   return true;
  }
 </script>

<form onsubmit="return chk(this);" method="post">
  <table>
   <tbody><tr><td>ID</td><td><input type="text" name="id" maxlength="32"></td><td class="ex">at least 4char</td></tr>
   <tr><td>PS</td><td><input type="password" name="ps" maxlength="32"></td><td class="ex">at least 7char</td></tr>
   <tr><td colspan="2"><input type="submit" value="join"></td></tr>
  </tbody></table>
 </form>

2


그래서 id와 ps를 각각 admin, admin12 를 넣어 가입해보면 admin은 이미 존재한다고 출력된다.

image-20240204164706981


Sign in 소스 코드는 아래와 같고 loginf() 함수를 사용중이다.

<div class="cont">
    have an account? <input type="button" onclick="loginf();" value="Sign in">
</div>

<script>
    function loginf() {
        var ab = document.getElementById("loginform");
        //ab.style.left=event.x;
        ab.style.left = 0;
        //ab.style.top=event.y;
        ab.style.top = 0;
        ab.style.display = "block";
    }
</script>


그래서 일단 계정을 guest, guestguest를 넣고 가입한 후 로그인을 시도해 보니 tmitter.php 로 이동된 것을 볼 수 있다.

image-20240204165717493


이 문제를 다시 한 번 살펴보면 id와 ps의 길이를 32로 제한하고 있는 것을 볼 수 있다. 처음 문제 설명에서 보았듯이 이 id와 ps는 char 이라는 자료형을 통해 값을 저장하게 되는데, 우리는 SQL을 처음 배울 때 varchar 함수를 사용했을 것이다. 따라서 char 자료형의 취약점을 통해서 익스플로잇을 할 수 있는데 char 자료형은 고정 문자열이기 때문에 사용자가 입력한 문자열을 제외하고는 공백으로 처리된다.

<form onsubmit="return chk(this);" method="post">
  <table>
   <tbody><tr><td>ID</td><td><input type="text" name="id" maxlength="32"></td><td class="ex">at least 4char</td></tr>
   <tr><td>PS</td><td><input type="password" name="ps" maxlength="32"></td><td class="ex">at least 7char</td></tr>
   <tr><td colspan="2"><input type="submit" value="join"></td></tr>
  </tbody></table>
 </form>
create table tmitter_user(
    idx int auto_increment primary key,
    id char(32),
    ps char(32)
);


따라서 이 32자를 넘어서 123을 입력하면 어떻게 될까? admin 123 을 입력한다고 했을 때 123이 33자리부터 입력되었다고 치면 요청되는 쿼리 부분에서는 동일하게 admin을 입력한 것과 똑같다. 따라서 이를 이용해 32자를 넘고 아무 문자나 숫자를 입력한 후 가입하면 flag를 획득할 수 있다.


admin과 공백 후 1자리를 1로 설정하기 위해 maxlength 값을 32에서 33으로 늘렸다. 따라서 스페이스바로 그냥 쭉 늘린 후 백스페이스하고 1을 입력하면 33자리를 입력할 수 있는 것이다. 비밀번호는 최소 7자리 이므로 1234567을 입력하였다.

image-20240204171054221

image-20240204171138891


위에서 말했던 것처럼 요청되는 쿼리는 admin으로 인식하기 때문에 admin, 1234567 을 입력해주면 flag를 획득할 수 있다.

image-20240204171307148

댓글남기기