[WARGAME][webhacking.kr] old-50

jckim22·2022년 11월 17일
0

[WEBHACKING] STUDY (WARGAME)

목록 보기
89/114

아래는 서버 코드이다.

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 50</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get>
id : <input name=id value='guest'><br>
pw : <input name=pw value='guest'><br>
<input type=submit>&nbsp;&nbsp;&nbsp;<input type=reset>
</form>
<?php
  if($_GET['id'] && $_GET['pw']){
    $db = dbconnect();
    $_GET['id'] = addslashes($_GET['id']); 
    $_GET['pw'] = addslashes($_GET['pw']);
    $_GET['id'] = mb_convert_encoding($_GET['id'],'utf-8','euc-kr');
    foreach($_GET as $ck) if(preg_match("/from|pw|\(|\)| |%|=|>|</i",$ck)) exit();
    if(preg_match("/union/i",$_GET['id'])) exit();
    $result = mysqli_fetch_array(mysqli_query($db,"select lv from chall50 where id='{$_GET['id']}' and pw=md5('{$_GET['pw']}')"));
    if($result){
      if($result['lv']==1) echo("level : 1<br><br>");
      if($result['lv']==2) echo("level : 2<br><br>");
    } 
    if($result['lv']=="3") solve(50);
    if(!$result) echo("Wrong");
  }
?>
<hr><a href=./?view_source=1>view-source</a>
</body>
</html>

45점 짜리 sql_Injection 문제였다.

코드를 찬찬히 해석했는데 먼저 addslashes함수에 대해서 자세히 알아봤다.
쿼터와 NULL에 앞에 슬래시를 붙여서 문자로 인식되게 하는 함수였다.
그리고 그 밑에 utf-8,euc-kr로 addslashes한 문자열을 인코딩하는 것을 볼 수 있었다.

고민을 하다가 addslashes 우회에 대해서 구글링 해보았다.
그렇게 공부한 바로는 euc-kr은 멀티바이트가 허용되는점을 이용하여 우회할 수 있다는 점을 알게되었다.

이게 무슨 말이었냐면 addslashes 자체로 우회가 어렵지만 멀티바이트를 쓸 수 있게 되면 슬래시를 1바이트 그리고 그 앞에 임의의 문자를 더하면서 2바이트로 문자 하나로 인식하게 만들어서 슬래시를 무효화 시키며 우회하는 것이었다.
이게 실제로 되는지 확인한것은 %a1%27을 id로 주고 요청을 보냈는데 쿼리가 정상적으로 전달된 반응인 wrong이 돌아왔다.
exit()가 아니였으므로 이것으로 쿼터 우회는 성공했다는 것은 알았다.

그리고 그 밑 코드를 보고 정규식을 하나 하나 구글링을 통해 해독할 수 있었겠지만 정확하게 하기 위해 사이트에서 정규식을 보기 좋게 바꾸었다.

바로 아래 문자들을 필터링하고 있었다.


그리고 그 밑에 id에서 union을 필터링하는 것을 보고 이번 문제에서는 union 사용도 불가능하겠구나 생각했다.
사실 이게 삽질에 가장 큰 이유중 하나였다.

코드로 돌아가면 결과값이 있어서 lv이 1이거나 2이면 출력을 해주고 3이면 solve해준다는 내용이었다.

정리하면 나는 addslashes를 멀티바이트를 이용해서 %a1을 쿼터를 인코딩한 %27앞에 붙여서 슬래시를 우회할 것이고 정규식 필터링을 피해서 sqlInjection을 성공해 lv=3의 값을 가져올 것이다.

먼저 메모장에 select lv from chall50 where id=''||(lv)like(3))#'이런식으로 복붙해서 어떻게 인젝션을 할지 구성했다.

처음으로 든 생각은 from도 안되고 union도 안되니 데이터 베이스에 lv=3에 값이 있을 거라고 생각하고 가져오려했다.
그래서 예전에 공부한 like를 사용하여 가져오려고 했다.
괄호 또한 우회해야해서 백쿼터도 쓰고 주석인 /**/으로 우회하려고 하다가 잘 되지 않았다.
이때까지는 주석이 크게 쓰일줄은 몰랐다.
그리고 주석으로 #을 쓰니까 자꾸 url상에서 pw가 서버로 보내지지 않아서 위치도 pw를 앞으로 하고 별짓을 다했다.

아무튼 내가 탭을 쓰지 않았던 이유는 썼다고 생각했는데 계속 안되어서 그랬다.
하지만 내가 어이없는 실수를 하고 있었다. 탭은 인코딩하면 %09인데 잠이 덜 깼는지 계속 /t로 뻘짓을 하고 있었던 것이다.

무튼 공백은 %09로 커버하기로 했다.
주석은 인코딩하면 %2F**%2F 인점도 참고하면서 공백 우회를 해보려고 했었다.

결과적으로는 %a1%27로 쿼터를 쓰고 그 뒤에 lv%09like%093%09--%09를 사용하여 lv=3의 값을 가져올 수 있을 것이라 생각했다.
아래를 보자 첫번째는 내가 뻘짓하다가 그 중에 하나를 찍은 것이고 두번째는 %a1%27lv%09like%093%09--%09으로 그나마 내가 적절한 우회 쿼리라고 생각했던 쿼리였다.

하지만 위에 쿼리의 결과는 아무것도 없었다 .....
wrong이 떴기 때문이다.
그렇다면 저번 문제와 똑같이 데이터베이스에 lv=3 자체가 혹시 없는걸까 하고 like2를 해본 결과 아래와 같이 나왔다.


위처럼 결과가 나온 것이다.
여기서 한번 더 생각에 잠겼던 것 같다.
union을 쓸 수 없는데 어떻게 자체적으로 row에 3을 넣을지 구글링을 계속했지만 쓸만한게 없었다.

그렇게 다시 코드를 보던 중 id뒤에는 pw가 오니까 공백이나 +를 이용해서 id와 pw의 쿼리를 이으면 되지 않을까 생각했다.
그래서 아래와 같이 했다.

하지만 역시 실패였다.

그래서 코드를 다시 살펴봤다.
근데 이상하게 union만 따로 정규식에서 빼고 union은 pw가 아니라 id에서만 필터링되고 있음을 눈치챘다.

그래서 긴 쿼리문을 아래처럼 블로그와 메모장에 갖고 와 봤다.

select lv from chall50 where id='{$_GET['id']}' and pw=md5('{$_GET['pw']}')

위 쿼리를 보면 내가 위해서 공백과 +로 id와 pw를 이으려고 했던게 정말 바보 같은 짓이었음이 보인다.
가운데 and pw=md5)'이 껴있는데 말이다.

만약 pw에서 unoin을 쓴다면 어떻게 해야할까 생각을 했다.
이렇게 메모장에서 길게 보니까 해답이 떠오를 때까지는 오래 걸리지 않았다.
왜냐면 아까 썼던 주석이 생각났기 때문이다.

설마하는 마음으로 코드를 조심스럽게 써보았다.

select lv from chall50 where id=''/*' and pw=md5('*/union select 3

위처럼 블로그에서 확인했는데 너무나도 말이 되는 코드였다.
그래서 바로 실행에 옮겼다.
아까 주석 인코딩을 구했던 것을 참고해서 아래와 같은 페이로드를 작성했다.

%a1%27%2F**%2Fnion%09select%093

결과는


실패였다.
이유가 뭘까 풀이를 너무 보고 싶었지만 참았다.

union에서 u를 빼먹었길래 그것때문인가 했다.

하지만 수정해도 wrong이었다.

그렇게 인코딩도 풀어보고 버프슈트로도 조작해보고 한 결과 ..

찾았다..

뒤에 주석처리를 안해주었다.

%a1%27%2F**%2Funion%09select%093%09--%09
이렇게 주석처리를 해주고 수정했더니

아래처럼

flag를 얻을 수 있었다.

문제 풀이를 직접적으로 보지는 않았지만 구글링을 통해 우회법이나 많은 공부들을 추가로 공부하지 않았으면 풀 수 없었던 문제였다. 지금까지 해왔던 공부들을 바탕으로 메모장과 블로그 코드부분에 길게 쿼리문을 쓰고 직접 이것저것 대입해보면서 한 눈에 쿼리가 보이면서 겨우 풀 수 있었던 문제였다.

profile
개발/보안

0개의 댓글