[wargame.kr] login filtering
Wargame 네 번째 문제 풀이 - Login filtering
안녕하세요. 오늘 풀어볼 문제는 login filtering입니다.
어느세 하나씩 올리다 보니까 네 번째 풀이가 됐네요.
모든 문제를 풀고 다른 사이트 문제를 정복하는 그날까지!!
이제 시작해 보겠습니다. ㅎㅎ

I have accounts. but, it's blocked. : 나는 계정을 가지고 있습니다. 하지만 차단당했어요.
can you login bypass filtering? : 당신은 필터링을 우회 할 수 있나요?
위처럼 해석이 되는데 문제를 보고 얻을 수 있는 힌트를 살펴 볼까요?
1. 계정을 가지고 있다.
2. 편법(우회)을 이용해 로그인을 한다.
이 두가지 정도를 생각해 보고 문제를 start 해보겠습니다.

시작을 하게되면 ID, PW 입력 폼, get source로 구성이 되어있는 페이지가 나옵니다.
일단 아래 보이는 get source를 무시하고 admin 1234, 1234 1234 부터 쳐보니 왼쪽 상단 처럼 'wrong..' 이라고 아련하게 써있네요.
get source를 한번 클릭해 볼까요?
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 | <?php if (isset($_GET['view-source'])) { show_source(__FILE__); exit(); } /* create table user( idx int auto_increment primary key, id char(32), ps char(32) ); */ if(isset($_POST['id']) && isset($_POST['ps'])){ include("../lib.php"); # include for auth_code function. mysql_connect("localhost","login_filtering","login_filtering_pz"); mysql_select_db ("login_filtering"); mysql_query("set names utf8"); $key = auth_code("login filtering"); $id = mysql_real_escape_string(trim($_POST['id'])); $ps = mysql_real_escape_string(trim($_POST['ps'])); $row=mysql_fetch_array(mysql_query("select * from user where id='$id' and ps=md5('$ps')")); if(isset($row['id'])){ if($id=='guest' || $id=='blueh4g'){ echo "your account is blocked"; }else{ echo "login ok"."<br />"; echo "Password : ".$key; } }else{ echo "wrong.."; } } ?> <!DOCTYPE html> <style> * {margin:0; padding:0;} body {background-color:#ddd;} #mdiv {width:200px; text-align:center; margin:50px auto;} input[type=text],input[type=[password] {width:100px;} td {text-align:center;} </style> <body> <form method="post" action="./"> <div id="mdiv"> <table> <tr><td>ID</td><td><input type="text" name="id" /></td></tr> <tr><td>PW</td><td><input type="password" name="ps" /></td></tr> <tr><td colspan="2"><input type="submit" value="login" /></td></tr> </table> <div><a href='?view-source'>get source</a></div> </form> </div> </body> <!-- you have blocked accounts. guest / guest blueh4g / blueh4g1234ps --> | cs |
저는 66번째 줄이 눈에 띄더라구요. 차단 당한 ID / PW중에 짧아서 그런지 먼저 쳐보게 됬어요.

음 역시나 로그인은 되지않아요. 그럼 다시 소스를 확인해 보겠습니다.
31~39 행을 보면 단순 입력받은 아이디와 직접 코드로 넣어둔 문자열이 같으면 차단 한다는 것을 확인할 수 있어요.
또한 그위에 행들의 대부분이 mysql_ 어쩌구로 시작하는 것으로 보아하니 DBMS는 MySQL이라는 것을 추측할 수 있겠네요.
뿐만 아니라 시작 행에 <?php>를 통해 php코드 라는 것을 알 수 있습니다. (php는 MySQL을 사용합니다.)
여기서 위에 정보를 가지고 '어떻게 플래그를 얻을 수 있을까?' 라는 고민을 하면서 감조차 오지 않는 분들이 많을거라 생각해요.
그럼, MySQL의 특징중 하나를 알려드릴게요.
MySQL은 기본적으로 대소문자를 구분하지 않습니다.
그렇다면 28행에 select문에 guest가 들어가든지 GUEST가 들어가든지 똑같은 결과 값이 나오겠죠?
즉,
select * from user where id='guest' and ps=md5('guest')
select * from user where id='GUEST' and ps=md5('guest')이 두개는 같은 쿼리 문이라고 할 수 있습니다.
if($id=='guest' || $id=='blueh4g') 우리는 이 조건문만 피해가면 되기때문에 'guest'가 아닌 어떤 Guest를 넣어도 상관이 없습니다. ㅎㅎ
한번 입력해볼까요?
저는 Guest / guest를 입력했습니다.

이렇게 MySQL의 특징의 취약점을 이용한 로그인 우회를 해서 문제를 풀 수 있었습니다.
추가적으로 '로그인 기능 / 회원가입 기능을 구현할 때 어떤 식으로 안전하게 코딩을 해야하는가.'에 대한 답변을 하자면
where 절에 binary를 추가하는 방법이 있습니다.
guest와 Guest의 2진코드는 엄연히 다른 값이 나오기 때문에 좀더 안전한 페이지를 만들 수 있습니다.
예를 들어 위의 select문을 다음과 같이 만드는 것이 가능합니다.
select * from user where binary id='$id' and ps=md5('$pw')
이렇게 해서 네 번째 문제 까지 풀이가 끝났습니다. 생각보다 쉽지 않나요?
다음은 WTF_CODE 라는 문제와 함게 찾아오겠습니다~
이번에도 열심히 따라와 주셔서 감사합니다ㅎㅎ