드디어 밀린 문제 풀이를 올립니다. 요즘 새로운 문제 푸는 게 손에 잡히지 않아서 복습도 할 겸 밀린 문제 풀이를 올려야겠네요! 이번 문제는 기초 SQL Injection 문제입니다. 문제를 열어보면 아래와 같은 화면을 보실 수 있습니다.

 SQL Injection 문제가 대부분 admin으로 로그인하는게 목표이므로 이 친구도 admin으로 로그인하면 풀릴 거라 쉽게 예상할 수 있습니다. 일단 view-source를 클릭해서 소스코드를 확인해보겠습니다.

<?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>

 GET 방식으로 no 값을 받고 no값에서 select, from, & 등 몇가지 문자에 대해서 필터링을 해주고 해당 문자가 아닐 경우

select id from chall18 where id='guest' and no=입력값

위와 같은 쿼리문을 서버에 보내서 result에 담고 result['id']가 admin일 경우에 문제가 풀리는 코드입니다. 친절하게 admin은 no=2라고 주석에 적혀있네요!

일단 where 조건으로 id가 guest로 고정되어 있으니 이 부분부터 거짓으로 만들어 조건 값을 초기화 시켜줘야겠습니다. no=2가 admin이라는 걸 알았으니 일단 아래처럼 첫 입력값으로 2를 넣어서 조건 값을 초기화시켜줍니다.

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

 파란 부분(id='guest')과 초록 부분(no=2)에 해당하는 값은 존재하지 않아 거짓이 되면서 결과값으로 아무런 값도 반환되지 않습니다. 그럼 이 상태에서 어떻게 admin id를 결과 값으로 반환시킬 수 있을까요? 간단합니다. 입력값 뒤에 새로운 조건을 넣어주면 됩니다.

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

 취소선 부분은 앞에서 거짓 처리되는 것을 확인했으니 where 부분을 새로 해석해보면 FALSE or no=2 가 됩니다. 이를 다시 해석하자면 아래와 같은 쿼리문이 서버로 날아가겠죠

select id from chall18 where no=2

 그리고 아까 코드 주석에서 admin의 no값은 2라고 친절하게 설명해줬으니 결과값에 result에 admin이 들어갈 거고 문제가 풀려야 합니다만.. 코드를 살펴보면 '공백'에 대한 필터링이 존재합니다. 그렇다고 입력값을 다 붙여 쓴다면 or를 인식하지 못하죠. 결국 '공백'과 같은 효과를 주면서 '공백'이 아닌 문자를 넣어줘야 합니다. 예를 들면 LF(LineFeed) 같은 문자가 있죠. 이제 LF를 입력값에 넣고 넘겨주기만 하면 됩니다. 다만 일반적인 입력방식으로는 LF를 넘기는 건 불가능하니 ASCII 코드를 이용하기로 합니다. 그럼 아래와 같은 쿼리문이 서버에 날아가겠죠

select id from chall18 where id='guest' and no=2%0aor%0ano=2

 그럼 아래와 같이 admin으로 로그인된 것을 확인할 수 있습니다. 끝!

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-19  (0) 2019.12.02
[Webhacking.kr] old-10  (0) 2019.10.29
[Webhacking.kr] old-06  (0) 2019.10.29
[Webhacking.kr] old-54  (0) 2019.10.22
[Webhacking.kr] old-26  (0) 2019.10.22

 

 문제를 클릭하면 위와 같이 id를 입력하는 부분이 있고 제출 버튼이 있습니다. 일단 기본값인 admin을 그대로 냅두고 제출 버튼을 누르면 you are not admin이라는 문구가 출력됩니다. 일단 다시 메인 페이지로 돌아와서 admin대신 a만 입력해보고 제출을 누르면

 

 위와 같이 hello a가 출력되고 로그아웃 버튼이 생깁니다. 이 상태에서 쿠키값을 확인해보면 아래와 같습니다.

 

 

 BASE64로 보이는 값이 userid에 들어가 있고 해당 값을 디코딩해보면 md5 값이 나옵니다. 그 값을 복호화 해보면 'a' 라는 값이 나옵니다.
결국 userid에 있는 base64는 입력된 문자를 md5로 변환하고 해당 값을 다시 base64로 인코딩 해준것이죠. 일단 대충 알았으니 입력 값을 바꿔서 테스트 해봅니다.

 

 

 입력값을 aa로 변경해서 확인해보면 앞부분이 이전 'a'만 입력했을 때와 동일하다는 것을 확인할 수 있습니다. base64를 디코딩 해보면 아까 확인했던 'a'의 md5 값이 연속해서 2번 찍혀있는 것을 확인할 수 있습니다. 그럼 결국 userid는 입력된 문자열의 각 문자마다 md5값을 구해서 그걸 이어 붙인 뒤 해당 값 전체를 base64로 인코딩 한것이라는 것을 알 수 있습니다. 저희는 admin으로 로그인(?)해야하니 admin의 각 문자들을 md5 값으로 변환해주고 해당 값들을 모두 붙인뒤 base64로 인코딩하여 userid 부분에 넣어주면 끝!

md5(a) = 0cc175b9c0f1b6a831c399e269772661
md5(d) = 8277e0910d750195b448797616e091ad
md5(m) = 6f8f57715090da2632453988d9a1501b
md5(i) = 865c0c0b4ab0e063e5caa3387c1a8741
md5(n) = 7b8b965ad4bca0e41ab51de7b31363a1

 

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-18  (0) 2020.03.16
[Webhacking.kr] old-10  (0) 2019.10.29
[Webhacking.kr] old-06  (0) 2019.10.29
[Webhacking.kr] old-54  (0) 2019.10.22
[Webhacking.kr] old-26  (0) 2019.10.22

 문제를 클릭하면 위와 같은 화면이 뜹니다. 0 위에 마우스를 올리면 y0u로 변하고 클릭하면 조금씩 전진합니다. 그리고 사진상엔 잘렸지만 회색칸 끝에는 골(Goal) 라인이 있습니다. 아마 0을 목표 지점까지 이동시키면 되는 문제 같은데 정확한 확인을 위해 소스를 살펴보겠습니다.

<html>
<head>
<title>Challenge 10</title>
</head>

<body>
<hr style=height:100;background:brown;>
<table border=0 width=1800 style=background:gray>
<tr><td>
<a id=hackme style="position:relative;left:0;top:0" onclick="this.style.left=parseInt(this.style.left,10)+1+'px';if(this.style.left=='1600px')this.href='?go='+this.style.left" onmouseover=this.innerHTML='yOu' onmouseout=this.innerHTML='O'>O</a><br>
<font style="position:relative;left:1600;top:0" color=gold>|<br>|<br>|<br>|<br>Goal</font>
</td></tr>
</table>
<hr style=height:100;background:brown;>
</body>
</html>

 

 a 태그 끝부분에 if문으로 위치가 1600px이면 문제가 풀리는 듯한 코드가 보입니다. 간단하게 개발자 도구를 이용하여 풀어보겠습니다.

 

 

 onclick 이벤트 부분에 +1+'px' 였던 것을 +1599+'px'로 변경한 뒤 클릭하면 깔끔하게 풀 수 있었습니다.

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-18  (0) 2020.03.16
[Webhacking.kr] old-19  (0) 2019.12.02
[Webhacking.kr] old-06  (0) 2019.10.29
[Webhacking.kr] old-54  (0) 2019.10.22
[Webhacking.kr] old-26  (0) 2019.10.22

 

 문제를 클릭하면 위 처럼 검정 화면에 view-source 링크, 그리고 ID와 PW가 적혀있는것을 확인할 수 있습니다. 문제를 어느정도 풀어보신 분이라면 위의 계정을 ADMIN으로 바뀌면 풀리는 문제겠구나~ 할 수 있을겁니다. 일단 확실하게 확인하기 위해 소스를 확인해보겠습니다.

 

<?php
include "../../config.php";
if($_GET['view_source']) view_source();
if(!$_COOKIE['user']){
  $val_id="guest";
  $val_pw="123qwe";
  for($i=0;$i<20;$i++){
    $val_id=base64_encode($val_id);
    $val_pw=base64_encode($val_pw);
  }
  $val_id=str_replace("1","!",$val_id);
  $val_id=str_replace("2","@",$val_id);
  $val_id=str_replace("3","$",$val_id);
  $val_id=str_replace("4","^",$val_id);
  $val_id=str_replace("5","&",$val_id);
  $val_id=str_replace("6","*",$val_id);
  $val_id=str_replace("7","(",$val_id);
  $val_id=str_replace("8",")",$val_id);

  $val_pw=str_replace("1","!",$val_pw);
  $val_pw=str_replace("2","@",$val_pw);
  $val_pw=str_replace("3","$",$val_pw);
  $val_pw=str_replace("4","^",$val_pw);
  $val_pw=str_replace("5","&",$val_pw);
  $val_pw=str_replace("6","*",$val_pw);
  $val_pw=str_replace("7","(",$val_pw);
  $val_pw=str_replace("8",")",$val_pw);

  Setcookie("user",$val_id,time()+86400,"/challenge/web-06/");
  Setcookie("password",$val_pw,time()+86400,"/challenge/web-06/");
  echo("<meta http-equiv=refresh content=0>");
  exit;
}
?>
<html>
<head>
<title>Challenge 6</title>
<style type="text/css">
body { background:black; color:white; font-size:10pt; }
</style>
</head>
<body>
<?php
$decode_id=$_COOKIE['user'];
$decode_pw=$_COOKIE['password'];

$decode_id=str_replace("!","1",$decode_id);
$decode_id=str_replace("@","2",$decode_id);
$decode_id=str_replace("$","3",$decode_id);
$decode_id=str_replace("^","4",$decode_id);
$decode_id=str_replace("&","5",$decode_id);
$decode_id=str_replace("*","6",$decode_id);
$decode_id=str_replace("(","7",$decode_id);
$decode_id=str_replace(")","8",$decode_id);

$decode_pw=str_replace("!","1",$decode_pw);
$decode_pw=str_replace("@","2",$decode_pw);
$decode_pw=str_replace("$","3",$decode_pw);
$decode_pw=str_replace("^","4",$decode_pw);
$decode_pw=str_replace("&","5",$decode_pw);
$decode_pw=str_replace("*","6",$decode_pw);
$decode_pw=str_replace("(","7",$decode_pw);
$decode_pw=str_replace(")","8",$decode_pw);

for($i=0;$i<20;$i++){
  $decode_id=base64_decode($decode_id);
  $decode_pw=base64_decode($decode_pw);
}

echo("<hr><a href=./?view_source=1 style=color:yellow;>view-source</a><br><br>");
echo("ID : $decode_id<br>PW : $decode_pw<hr>");

if($decode_id=="admin" && $decode_pw=="nimda"){
  solve(6);
}
?>
</body>
</html>

 

 쿠키에 유저 값이 없으면 val_id에 guest, val_pw에 123qwe를 넣고 각각 20번씩 base64 인코딩을 해줍니다. 그 뒤에 인코딩된 문자열을 가지고 1~8을 !~*로 변경하는 간단한 작업을 거친 뒤 해당 값을 쿠키값으로 세팅을 합니다. 그 후에 페이지를 로드하면서 위에서 했던 작업과 정확히 반대되는 작업을 진행하고 해당 작업의 결과물을 ID와 PW로 출력해줍니다. 그리고 그 밑에 디코딩된 id와 pw가 각각 admin, nimda면 문제가 풀리는 코드입니다.

 어쩃든 최종 결과값이 admin이랑 nimda면 풀리는 문제인데 코드의 윗부분을 살펴보면 쿠키값에 user가 세팅되어 있지 않을 경우에만 위쪽의 코드가 동작하고 user가 세팅되어 있을경우 아래에 있는 디코딩 부분만 동작하는 것을 확인할 수 있습니다. 그럼 결국 저희는 admin과 nimda를 위의 방식대로 인코딩한 값을 구해서 쿠키에 넣어주면 문제를 풀 수 있습니다.

 풀이 방법이야 간단하겠지만 저는 Gnuboard 1-Day 떄문에 쓰고 있는 웹서버가 있기 때문에 해당 서버에 위의 코드를 그대로 긁어서 살짝 수정해서 admin, nimda의 인코딩 결과 값을 출력하게 만들어줬습니다. 그리고 그 값 그대로 긁어서 쿠키에 넣어서 간단하게 풀 수 있었습니다. 아래가 제가 풀이에 사용한 코드입니다.

 

<?php
$val_id="admin";
$val_pw="nimda";

for($i=0;$i<20;$i++){
  $val_id=base64_encode($val_id);
  $val_pw=base64_encode($val_pw);
}
$val_id=str_replace("1","!",$val_id);
$val_id=str_replace("2","@",$val_id);
$val_id=str_replace("3","$",$val_id);
$val_id=str_replace("4","^",$val_id);
$val_id=str_replace("5","&",$val_id);
$val_id=str_replace("6","*",$val_id);
$val_id=str_replace("7","(",$val_id);
$val_id=str_replace("8",")",$val_id);

$val_pw=str_replace("1","!",$val_pw);
$val_pw=str_replace("2","@",$val_pw);
$val_pw=str_replace("3","$",$val_pw);
$val_pw=str_replace("4","^",$val_pw);
$val_pw=str_replace("5","&",$val_pw);
$val_pw=str_replace("6","*",$val_pw);
$val_pw=str_replace("7","(",$val_pw);
$val_pw=str_replace("8",")",$val_pw);
echo '<p>user is<br>'.$val_id.'</p>';
echo '<p>password is<br>'.$val_pw.'</p>';

$decode_id=$val_id;
$decode_pw=$val_pw;

$decode_id=str_replace("!","1",$decode_id);
$decode_id=str_replace("@","2",$decode_id);
$decode_id=str_replace("$","3",$decode_id);
$decode_id=str_replace("^","4",$decode_id);
$decode_id=str_replace("&","5",$decode_id);
$decode_id=str_replace("*","6",$decode_id);
$decode_id=str_replace("(","7",$decode_id);
$decode_id=str_replace(")","8",$decode_id);

$decode_pw=str_replace("!","1",$decode_pw);
$decode_pw=str_replace("@","2",$decode_pw);
$decode_pw=str_replace("$","3",$decode_pw);
$decode_pw=str_replace("^","4",$decode_pw);
$decode_pw=str_replace("&","5",$decode_pw);
$decode_pw=str_replace("*","6",$decode_pw);
$decode_pw=str_replace("(","7",$decode_pw);
$decode_pw=str_replace(")","8",$decode_pw);

for($i=0;$i<20;$i++){
  $decode_id=base64_decode($decode_id);
  $decode_pw=base64_decode($decode_pw);
}
echo("ID : $decode_id<br>PW : $decode_pw<hr>");
?>

 

끝!

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-19  (0) 2019.12.02
[Webhacking.kr] old-10  (0) 2019.10.29
[Webhacking.kr] old-54  (0) 2019.10.22
[Webhacking.kr] old-26  (0) 2019.10.22
[Webhacking.kr] old-25  (0) 2019.10.22

 

 문제를 클릭하면 Password is 하고 플래그가 순식간에 호다다다다다닥 지나가버립니다. 동체시력과 기억력이 좋으신분이라면 그냥 여러번 새로 고침해서 푸셔도 됩니다..? 만 그러라고 있는 문제는 아닙니다. 일단 소스코드를 봅니다.

 

<html>
<head>
<title>Challenge 54</title>

</head>
<body>
<h1><b>Password is <font id=aview></font></b></h1>
<script>
function run(){
  if(window.ActiveXObject){
   try {
    return new ActiveXObject('Msxml2.XMLHTTP');
   } catch (e) {
    try {
     return new ActiveXObject('Microsoft.XMLHTTP');
    } catch (e) {
     return null;
    }
   }
  }else if(window.XMLHttpRequest){
   return new XMLHttpRequest();
 
  }else{
   return null;
  }
 }
x=run();
function answer(i){
  x.open('GET','?m='+i,false);
  x.send(null);
  aview.innerHTML=x.responseText;
  i++;
  if(x.responseText) setTimeout("answer("+i+")",20);
  if(x.responseText=="") aview.innerHTML="?";
}
setTimeout("answer(0)",1000);
</script>
</body>
</html>

 

 answer함수에서 flag값을 호다닥 출력해준다는 것을 확인할 수 있습니다. 개발자 콘솔을 열어서 시간이 다 지나면 flag가 이쁘게 출력하도록 함수를 재정의 해줘서 풀면 끝날것 같습니다.

 위처럼 짜주면 시간이 다 지나도 ? 대신에 플래그가 이쁘게 뿅 하고 튀어나옵니다.

 

끝!

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-10  (0) 2019.10.29
[Webhacking.kr] old-06  (0) 2019.10.29
[Webhacking.kr] old-26  (0) 2019.10.22
[Webhacking.kr] old-25  (0) 2019.10.22
[Webhacking.kr] old-24  (0) 2019.10.22

 

 문제를 클릭하면 아무것도 없고 view-source만 있습니다. 소스를 보도록 합니다.

 

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 26</title>
<style type="text/css">
body { background:black; color:white; font-size:10pt; }    
a { color:lightgreen; }
</style>
</head>
<body>
<?php
  if(preg_match("/admin/",$_GET['id'])) { echo"no!"; exit(); }
  $_GET['id'] = urldecode($_GET['id']);
  if($_GET['id'] == "admin"){
    solve(26);
  }
?>
<br><br>
<a href=?view_source=1>view-source</a>
</body>
</html>

 

 GET 방식으로 id 값을 넘겨 받고 해당 값이 admin이면 no! 를 출력하며 끝납니다. 하지만 admin이 아닐경우 id에 id값을 URL 디코딩하여 다시 넣어주고 해당 값이 admin이면 solve를 호출합니다. 그래서 admin을 URL인코딩해서 넘기면 되는데.. 해보시면 아시겠지만 그냥 admin으로 인식해버려서 no! 가 출력되버립니다. 즉, id값을 처음 검증할때 이미 한번 디코드한다는 뜻이니 인코딩을 2번하면 됩니다.

 

%61%64%6D%69%6E -> URL decode -> admin -> 첫번째 조건문에 걸림 -> no!

%2561%2564%256D%2569%256E -> URL decode -> %61%64%6D%69%6E -> 첫번째 조건문 패스 -> URL decode -> admin

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-06  (0) 2019.10.29
[Webhacking.kr] old-54  (0) 2019.10.22
[Webhacking.kr] old-25  (0) 2019.10.22
[Webhacking.kr] old-24  (0) 2019.10.22
[Webhacking.kr] old-17  (0) 2019.10.22

 

 정말 고생했던 문제입니다.. 분명 150점 짜리이고 리메이크 되기전에 간단하게 풀었던 문제인데 몇시간을 투자해도 도저히 풀 수 없어서 그냥 rubiya님께 문의해서 힌트를 받아서 풀 수 있었습니다.. 때문에 이 문제 풀이는 접은글로 닫아두고 제가 rubiya님에게 받은 힌트를 보여드리겠습니다. 해당 힌트를 참고해서 풀어보시고 그래도 모르시겠다면 접은 글을 참고하시면 될것 같습니다.

[힌트]
https://www.php.net/manual/en/wrappers.php.php

 

PHP: php:// - Manual

This parameter takes one or more filternames separated by the pipe character |.

www.php.net

[추가 힌트]
제가 드리는 추가 힌트입니다.

1. 위의 페이지에서 filter 를 사용합니다
2. php wrapper vuln 을 키워드로 검색하시면 관련 자료들이 나옵니다.

 

[풀이]

...더보기

 이 문제는 PHP Wrapper 중 filter를 이용하면 풀 수 있습니다. filter의 기능중에 base64 인코딩 기능이 있는데 이를 이용해서 flag,php를 인코딩 시키면 저 텍스트 박스에 php 소스가 base64로 인코딩된 값이 출력됩니다. 해당 값을 decode하고 flag값을 인증하면 끝!

http://webhacking.kr:10001/?file=php://filter/convert.base64-encode/resource=flag

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-54  (0) 2019.10.22
[Webhacking.kr] old-26  (0) 2019.10.22
[Webhacking.kr] old-24  (0) 2019.10.22
[Webhacking.kr] old-17  (0) 2019.10.22
[Webhacking.kr] old-16  (0) 2019.10.22

 

 문제를 클릭하면 위처럼 client ip와 agent 값이 출력되고 끝입니다. 소스를 확인해봅니다.

 

<?php
  extract($_SERVER);
  extract($_COOKIE);
  $ip = $REMOTE_ADDR;
  $agent = $HTTP_USER_AGENT;
  if($REMOTE_ADDR){
    $ip = htmlspecialchars($REMOTE_ADDR);
    $ip = str_replace("..",".",$ip);
    $ip = str_replace("12","",$ip);
    $ip = str_replace("7.","",$ip);
    $ip = str_replace("0.","",$ip);
  }
  if($HTTP_USER_AGENT){
    $agent=htmlspecialchars($HTTP_USER_AGENT);
  }
  echo "<table border=1><tr><td>client ip</td><td>{$ip}</td></tr><tr><td>agent</td><td>{$agent}</td></tr></table>";
  if($ip=="127.0.0.1"){
    solve(24);
    exit();
  }
  else{
    echo "<hr><center>Wrong IP!</center>";
  }
?>

 

 저는 이미 풀어져있는 문제라 후배 블로그에서 소스코드를 긁어왔습니다. extract 함수를 이용해 $_SERVER와 $_COOKIE를 가져오는데 두 변수는 PHP 예약 변수로 각각 서버(혹은 실행환경)의 정보를 담고 있는 배열과 쿠키의 정보를 담고 있는 배열입니다. 그 후 ip에 REMOTE_ADDR 값을, agent에 HTTP_USER_AGENT 값을 넣어줍니다.

 그 뒤에 ip값을 특정 조건에 맞게 변환해준 뒤 해당 ip값이 127.0.0.1이면 solve를 호출하는 방식입니다. 이 문제의 취약점은 $_SERVER를 추출해온 뒤 $_COOKIE를 추출했다는 부분입니다. $_SERVER를 추출할때 REMOTE_ADDR값을 가져왔는데 $_COOKIE를 추출할때 쿠키 값에 똑같이 REMOTE_ADDR 값이 존재한다면 해당 값을 쿠키에 있던 값으로 덮어 씌웁니다.

 대충.. 이런느낌?

위와 같은 취약점 때문에 쿠키값에 REMOTE_ADDR 값을 넣고 위의 조건에 맞춰서 127.0.0.1이 되게 만들어주면 됩니다.

 

끝!

'Web Hacking > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] old-26  (0) 2019.10.22
[Webhacking.kr] old-25  (0) 2019.10.22
[Webhacking.kr] old-17  (0) 2019.10.22
[Webhacking.kr] old-16  (0) 2019.10.22
[Webhacking.kr] old-14  (0) 2019.10.22

+ Recent posts