LJ

Lord of SQLinjection ( 8번 ) troll 본문

IT 보안/보안첼린지

Lord of SQLinjection ( 8번 ) troll

짱준재 2024. 5. 23. 10:41

 

 

 

 

 

troll 문제이다.

 

굉장히 쉬우므로 빠르게 소스코드 분석부터 해보자

 

<?php

//PHP 코드의 시작
include "./config.php";

//config.php 파일을 포함하여 데이터베이스 연결 정보와 같은 설정을 불러온다.
login_chk();

//login_chk 함수를 호출하여 사용자가 로그인했는지 확인하고 이 함수는 인증과 관련된 작업을 수행
$db = dbconnect();

//dbconnect 함수를 호출하여 데이터베이스에 연결하고, 연결 객체를 $db 변수에 저장
if(preg_match('/\'/i', $_GET['id'])) exit("No Hack ~_~");

//PHP Regular Expression Match
//$_GET['id']에 작은 따옴표(')가 포함되어 있는지 정규 표현식으로 검사
//작은 따옴표가 발견되면 "No Hack _" 메시지를 출력하고 스크립트를 종료.
//SQL 인젝션을 방지하려는 시도
if(preg_match("/admin/", $_GET['id'])) exit("HeHe");

//$_GET['id']에 "admin"이라는 문자열이 포함되어 있는지 정규 표현식으로 검사.
//"admin"이 발견되면 "HeHe" 메시지를 출력하고 스크립트를 종료
//"admin" 계정에 대한 접근을 방지하려는 시도
$query = "select id from prob_troll where id='{$_GET['id']}'";

//사용자의 입력값을 포함한 SQL 쿼리를 생성
//이 쿼리는 prob_troll 테이블에서 id가 사용자의 입력값과 일치하는 행을 선택
echo "<hr>query : <strong>{$query}</strong><hr><br>";

//생성된 쿼리를 화면에 출력
//디버깅 목적으로 사용되며, 실제 배포 환경에서는 제거하는 것이 좋다.
$result = @mysqli_fetch_array(mysqli_query($db, $query));

//데이터베이스에 쿼리를 실행하고, 결과를 배열로 가져옴.
//@ 연산자는 오류를 무시하도록 한다.
if($result['id'] == 'admin') solve("troll");

//쿼리 결과에서 id가 "admin"인지 확인.
//만약 id가 "admin"이면, solve 함수를 호출하여 특정 작업을 수행한다. 여기서는 "troll"을 인자로 전달
highlight_file(__FILE__);

//__FILE__ :현재 파일의 전체 경로와 파일명을 나타내는 PHP 매직 상수
//첫 번째 인자로 파일 경로를 받으며, 두 번째 인자로 true를 지정하면, 하이라이트된 코드를 반환하고, false (기본값)일 경우, 결과를 바로 출력
//PHP 내장 함수로, 지정된 파일의 소스 코드를 읽어 들여서 HTML로 구문 강조된 형식으로 출력
//디버깅이나 문제 해결 목적으로 사용

 

 

 

 

소스코드를 확인했을 때 id 파라미터에 admin을 삽입해야 하는데

 

admin을 필터링 하는 아이러니한 상황이다.

 

그치만 admin을 대소문자 구분없이 필터링하는 것이 아닌 소문자만 필터링하므로 

 

 

admin 중 하나 이상을 대문자로 바꿔 전송하면 문제가 해결된다.

 

( MySql은 대소문자 구분을 하지 않기 때문에, admin이나 ADMIN이나 같은 문자열로 인식 )

 

 

 

 

 

 

 

 

 

글이 짧아 위의 코드를 안전한 코드로 바꿔보겠다

 

<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();

  $id = $_GET['id'];
  
  //사용자가 GET 요청으로 전달한 id 값을 $id 변수에 저장
  
  if(preg_match('/\'/i', $id)) exit("No Hack ~_~");
  if(preg_match("/admin/", $id)) exit("HeHe");

  // Prepare statement to prevent SQL injection
  $stmt = $db->prepare("SELECT id FROM prob_troll WHERE id = ?");
  //SQL 인젝션을 방지하기 위해 준비된 문(Prepared Statement)을 생성
  //?는 플레이스홀더로, 실제 값은 나중에 바인딩
  $stmt->bind_param("s", $id);
  //bind_param 메서드를 사용하여 SQL 쿼리의 플레이스홀더(?)에 $id 값을 바인딩
  //"s"는 바인딩할 값이 문자열임을 나타냄
  $stmt->execute();
  //준비된 문을 실행
  $result = $stmt->get_result()->fetch_assoc();
  //get_result 메서드는 실행된 쿼리의 결과를 mysqli_result 객체로 반환
  //쿼리 실행 결과를 가져와서 연관 배열로 반환
  //get_result 메서드는 쿼리 결과 객체를 반환하고, fetch_assoc 메서드는 그 결과를 연관 배열로 변환
  //$result = array(
  //  "id" => "admin"
  //      );

  if($result && $result['id'] == 'admin') solve("troll");

  highlight_file(__FILE__);
?>

 

 

 

  • SQL 인젝션: 사용자의 입력값을 직접 쿼리에 포함시키는 것은 매우 위험하므로 이를 방지하기 위해 준비된 문(Prepared Statement)을 사용하는 것이 좋다.
  • 에러 처리: @ 연산자를 사용하여 오류를 무시하지 말고, 적절한 에러 처리를 구현해야 한다.
  • 디버깅 코드 제거: 쿼리를 출력하는 echo 문과 소스 코드를 출력하는 highlight_file 함수는 실제 배포 환경에서는 제거하는 것이 좋다.

 

 

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

Lord of SQLinjection ( 11번 ) golem  (0) 2024.05.28
Lord of SQLinjection ( 9번 ) vampire  (0) 2024.05.23
XSS game level 6  (0) 2024.05.20
XSS game level 5  (0) 2024.05.20
XSS game level4  (0) 2024.05.17
Comments