왠일로 비교적 풍족한 화면입니다. 입력창도 오랜만에 보네요.

큰 폰트로 "SQL INJECTION" 이라고 적힌걸 보니 sql문으로 하는 인젝션 문제인거같네요. 

바로 코드를 보겠습니다.

 

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 18</title>
<style type="text/css">
body { background:black; color:white; font-size:10pt; }
input { background:silver; }
a { color:lightgreen; }
</style>
</head>
<body>
<br><br>
<center><h1>SQL INJECTION</h1>
<form method=get action=index.php>
<table border=0 align=center cellpadding=10 cellspacing=0>
<tr><td><input type=text name=no></td><td><input type=submit></td></tr>
</table>
</form>
<a style=background:gray;color:black;width:100;font-size:9pt;><b>RESULT</b><br>
<?php
if($_GET['no']){
  $db = dbconnect();
  if(preg_match("/ |\/|\(|\)|\||&|select|from|0x/i",$_GET['no'])) exit("no hack");
  $result = mysqli_fetch_array(mysqli_query($db,"select id from chall18 where id='guest' and no=$_GET[no]")); // admin's no = 2

  if($result['id']=="guest") echo "hi guest";
  if($result['id']=="admin"){
    solve(18);
    echo "hi admin!";
  }
}
?>
</a>
<br><br><a href=?view_source=1>view-source</a>
</center>
</body>
</html>

 

코드가 좀 길어보이지만 아래쪽 php 코드 부분이 제일 중요해보이네요. 그 부분만 보겠습니다.

 

<?php
if($_GET['no']){
  $db = dbconnect();
  if(preg_match("/ |\/|\(|\)|\||&|select|from|0x/i",$_GET['no'])) exit("no hack");
  $result = mysqli_fetch_array(mysqli_query($db,"select id from chall18 where id='guest' and no=$_GET[no]")); // admin's no = 2

  if($result['id']=="guest") echo "hi guest";
  if($result['id']=="admin"){
    solve(18);
    echo "hi admin!";
  }
}
?>

 

GET 방식으로 "no" 파마리터를 입력받을 때 preg_match 함수를 사용하여 특수문자와 select 등을 필터링 하고있습니다.

지정된 정규표현식에 해당하는 문자가 들어오면, "no hack"을 출력합니다.

SQL문의 where절에 "no"를 받아와 그 결과를 result에 넣은 후 그 결과가 guest면 "hi guest"를 출력하고, admin이면 문제가 해결되며 "hi admin"가 출력됩니다.

 

쭉 읽어보니 필터링을 우회해서 result에 admin값을 넣으면 해결되는것 같네요.

주석을 보니 admin의 no값이 2라고합니다.

 

select id from chall18 where id='guest' and no=$_GET[no]

 

SQL문을 보면 no= 다음 부분부터 GET 방식으로 입력을 받고 있습니다. 또한 where절에 id가 guest로 작성되어있으니...

위에 코드에서 본것처럼 id가 admin일때 해결된다는 코드를 방해하고있네요.

고로 where절을 무력화 시키면서 no에 2를 넣거나, id에 admin값을 넣거나 하면 되겠네요.

 

no에 2를 넣는 것 부터 해보겠습니다.

and연산자로 id와 no를 구분하고있기 때문에 no부분을 알맞지 않는 값으로 바꾸면 where절의 앞부분은 false가 됩니다.

그 뒤에 or연산자로 true인 값을 넣으면 "false(0) or true(1)" 가 되어 결국 true가 되겠네요.

때문의 sql의 문 자체는 true만들어서 실행되게 만들고, 방해되는 부분은 false로 만들어서 치운 뒤 우리가 원하는 데이터를 출력하게 하도록 그 부분만 true로 만들면 되겠습니다.

 

 

no값에 1을 넣었을 때 "hi guest"라는 문자열이 출력 되었습니다. 1이외의 숫자에는 반응을 안하네요.

즉 guest의 no값은 1이라는걸 알게되었습니다.

 

select id from chall18 where id='guest' and no=1

 

1을 입력했을 때 결과적으로 위와 같은 sql문이 완성되어 "hi guest"를 출력한 것 입니다. 그럼 이를 이용해서..

 

select id from chall18 where id='guest' and no=3 or no=2

 

이런식으로 입력하면 어떻게 될까요?

 

 

위와 같이 id가 guest일땐 no가 1이기에 3이 입력되면 그 식은 false가 되지만... no가 2인것 자체는 true가 됩니다.

단순이보면 admin의 no가 2라는것도 알려줬고, 데이터베이스에 no가 2인 값이 있으니까요.

때문에 두 식을 or연산으로 다시 계산하면 0(false) or 1(true) = 1(true)가 되어 sql문의 where절은 오류없이 실행되고, true부분인 no=2만 식에 남게되어

select id from chall18 where no=2

 

false인 부분은 의미가 없어지고 위와 같은 식이 됩니다. 저대로라면 no가 2인 id를 불러올테니 admin이 리턴되고, 문제가 해결되겠네요.

이제 입력을 해보면..

 

 

no hack이라 출력됩니다. 왜냐하면 위에 필터링에 공백도있었기 때문이죠.

하고 url을 보니.. 어라? 뭔가 이상하죠.

이번엔 입력창이 아니라 주소창 url에 바로 입력해보겠습니다.

url에 표기되는 값이 다르네요?

이를통해 입력창에 입력시 url인코딩이 된다는걸 알 수 있습니다.

공백이 +로, =은 %3D로 인코딩되어 원하는 값을 넣기 힘들지만

아래 사진을 보면 공백만 %20으로 필터링되는걸 알 수 있습니다.

그렇다면 입력창이 아닌 url에 공백만 우회해서 넣으면 끝일것 같네요.

 

공백 우회방법은 여러가지가있는데, 그중 %09로 공백을 대채해보았습니다.

 

이미 해결한 상태라 응답이 다르네요.

짠! 문제 해결입니다.

 

문제 해결 방법이 하나 더 있었죠.

위에서 말한것 처럼 코드를 잘 보면 id가 admin이라면 문제가 해결된다고합니다.

그럼 no=2대신 id="admin"을 넣어도 문제가 풀린다는 뜻이죠.

select id from chall18 where id='guest' and no=3 or id="admin"

 

아니나 다를까 해결되는 걸 볼 수 있었습니다.

 

사실 no=2로 푸는 것 보다 id=admin을 넣은 sql문으로 먼저 풀었는데...

힌트도 그렇고 no를 2로 넣어서 푸는것이 정석에 가까운것 같아 더 길게 적어보았습니다.

'보안 > 워게임 (웹 해킹)' 카테고리의 다른 글

Challenge - old-03 write up  (0) 2025.03.31
Challenge - old-24 write up  (0) 2025.03.24
Challenge - old-26 write up  (0) 2025.03.17
Challenge - old-16 write up  (0) 2025.03.17
Challenge - old-6 write up  (0) 2025.03.13

+ Recent posts