SlowTurtle_

천천히 그러나 끝까지 완주

Webhacking-Write-Up/Webhacking.kr

[Webhacking.kr] 24, 25, 26, 27, 32 문제

SlowTurtle_ 2023. 1. 13. 09:38
728x90

24번 문제

코드를 보자.

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 24</title>
</head>
<body>
<p>
<?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>";
  }
?><hr>
<a href=?view_source=1>view-source</a>
</body>
</html>

해결은 간단하다 ip가 127.0.0.1이면 해결된다. 그럼 해결하기위해 다른 코드들을 해석해보자.

extract함수는 배열의 키값들을 변수화 시킨다. 그리고 $ip 변수에는 $REMOTE_ADDR의 값이 저장되어 있음을 알 수 있다. if절은 $REMOTE_ADDR 값이 존재할 때 실행한다. 또한 .., 12, 7., 0. 을 replace함수를 사용해 치환 시킨다. 즉, REMOTE_ADDR의 변환 값이 127.0.0.1이면 해결이다. 우리는 COOKIE값을 변경할 수 있으니 그것을 이용해보자.

개발자 모드에 들어가 원래 있던 쿠키의 Name을 REMOTE_ADDR로 변경하고 Value에 112277...00...00...1값을 넣었다.

Value에 저런 값을 넣은 이유는 replace함수로 치환되는 것들은 한 번만 치환시키기 때문이다. 

쿠키값을 넣은 후 새로고침하면?

해결했다.

 

25번 문제

URL을 보니 GET방식임을 알 수 있었다. 바로 hello.php를 hello로 입력되어있는데 출력되는 것을 보고 flag를 입력해봤다.

FLAG는 코드안에 있다. 근데 어떻게 볼까싶어 개발자모드도 켜보고 소스코드도 보고했는데 힌트조차 찾을 수 없었다. 구글링해보니 php파일은 php wrapper에서 php://filter를 통해서 다양한 I/O스트림을 다룰 수 있다고 한다. 또한 encode/decode옵션을 사용해서 서버 안에 문서들을 열람할 수 있다. 우리는 encode를 통해서 서버 안에 문서를 열람해보자. 주소/?page=php://filter/convert.base64-encode/resource=파일이름 형식으로 사용할 수 있다.(출처 https://opentutorials.org/module/4291/26819)

 

LFI(2) - with php wrapper - WEB1

이번 시간에는 php wrapper를 사용한 lfi에 대해 알아보도록 하겠습니다.  우선 wrapper란 실제 데이터의 앞에서 어떤 틀을 잡아 주는 데이터 또는 다른 프로그램이 성공적으로 실행되도록 설정하는

opentutorials.org

따라서 php://filter/convert.base64-encode/resource=flag 를 입력하면

사진과 같이 base64로 인코딩 된 flag값을 알 수 있다. base64 디코딩을 해보자.

flag값을 알았으니 Auth에 flag값을 입력하면

해결했다.

 

26번 문제

코드를 보자.

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

id를 GET방식으로 받고 받은 값이 admin이면 해결된다. preg_match함수로 /admin/을 필터링하고 있으니 admin을 직접 입력은 하지 못한다. 필터링을 피하면 받은 id값을 urldecode한다. 그러면 admin을 인코딩하면 될 것같다. admin  url인코더를 사용하면 값이 안나오니 url인코딩 표를 보고 구한 값은 %61%64%6d%69%6e이다. url에 넣었더니

no!가 떴다. 가장 기본적인 것을 간과했는데 서버로 보낼 때 한 번 디코딩해서 보내지는 것이다. 그러니까 인코딩을 한 번 더해야 서버로 넘어간 값이  %61%64%6d%69%6e이 될 것이다. 따라서 %61%64%6d%69%6e을 한 번 더 인코딩했다.

%2561%2564%256D%2569%256E 를 입력하니

해결했다.

 

27번 문제

코드를 보자.

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 27</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get action=index.php>
<input type=text name=no><input type=submit>
</form>
<?php
  if($_GET['no']){
  $db = dbconnect();
  if(preg_match("/#|select|\(| |limit|=|0x/i",$_GET['no'])) exit("no hack");
  $r=mysqli_fetch_array(mysqli_query($db,"select id from chall27 where id='guest' and no=({$_GET['no']})")) or die("query error");
  if($r['id']=="guest") echo("guest");
  if($r['id']=="admin") solve(27); // admin's no = 2
}
?>
<br><a href=?view_source=1>view-source</a>
</body>
</html>

SQL Injection문제다. 우선 id가 admin이면 해결된다. 그러나 preg_match로 많은 것들을 필터링하고 있다. no를 GET방식으로 입력 받는데 받은 no의 id가 guest가 아니면 query error를 출력한다. admin's no = 2라는 주석을 보니 no = 1은 guest인가보다.

맞다. 그럼 no = 2를 해보면

guest가 아니라 query error가 뜬다.

어차피 "select id from chall27 where id='guest' and no=~ 으로 id = guest가 되어있으니 뒤에 no을 2로 입력받으면 되는데(받은no값) 이러한 형식이다. 그러면 or no = 2을 넣게 되면  (or no = 2)가 되어버리니 2 뒤에 #을 넣는다. 그러면 (or no =2# )")) ~~~이 되는데 ( 열린 괄호 하나 남으니 0) or no = 2 #으로 쿼리문을 작성할 수 있겠다. 근데 여기서 preg_match를 생각하여 필터링을 우회하는 것을 생각해보면 공백, 등호, #이 있다. 공백은 %09 (tap을 url인코딩)으로 바꾸고 등호는 like로 바꾼 뒤 #은 -- -으로 바꿀 수 있다. 그러면

0)%09or%09no%09like%092%09--%09-

위와같이 쿼리문을 작성할 수 있다. 보내보자.

해결했다.

 

32번 문제

클릭하면 ?hit=id로 투표가 된다.

한 번 투표하면 더 안되는 이유를 찾기 위해서 개발자모드를 켜서 쿠키를 봤다.

value에 ok가 있었다. 이것을 지우면 다시 투표를 할 수 있었다. 100번 이 짓을 할 수 없으니 파이썬 스크립트를 간단하게 짜봤다.

import requests

url = "https://webhacking.kr/challenge/code-5/?hit=SlowTurtle"
cookies = {"PHPSESSID" : "mi8fl44ecpi1nfsffb2laop93d"}

for i in range(99) : 
    requests.get(url, cookies = cookies)

새로고침을 하다가 99에 됐을 때 내가 눌렀더니

 

해결했다.

 

728x90