728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)|#|-/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(strlen($_GET[pw])>6) exit("No Hack ~_~"); 
  $query = "select id from prob_nightmare where pw=('{$_GET[pw]}') and id!='admin'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id']) solve("nightmare"); 
  highlight_file(__FILE__); 
?>

답: ?pw=')=0;%00

query : select id from prob_nightmare where pw=('')=0;') and id!='admin'

이런 쿼리가 완성이 되는데 해석하자면 pw=('')=0까지 실행된다. ;%00은 쿼리의 끝을 의미한다고 보면 된다. 주석을 대신하는 용도로 많이 사용된다. 따라서 남은 뒷부분은 무시된다. 참고로 %00은 php의 strlen 함수에서 길이 1로 취급한다.

pw=('')=0 은 앞에서부터 순차적으로 비교한다. pw=('')을 비교하는데 괄호는 무시해도 된다. 구분자의 역할이기 때문이다. 결국 빈 문자열과 pw를 비교하는 것이다. pw가 빈 문자열인 경우는 없을 것이라 pw=('')은 0을 반환하고 다시 뒤에 0과 =연산 끝에 1이 반환된다. 즉 모든 행에 대하여 참이 되는 것이다. 따라서 어떤 id 하나는 최종적으로 얻게 된다.

이 문제 해설들에서 ('')이 0과 같아서 위의 쿼리가 실행되어 문제가 풀린다는 글이 보이는데 이건 잘못됐다. 문자열과 정수의 비교 연산에선 형변환이 진행되지만 테스트해보면 pw=('')=0에서 앞에서부터 진행된다. pw도 문자열, ('')도 문자열이기에 형변환 없이 문자열끼리의 비교연산이 된다. 그 결과 pw가 빈 문자열인 경우는 없다고 보고 연산결과 0이 반환될 것이고 마지막 =0 연산에서 최종적으로 1(참)이 반환될 것이다.

참고 자료)

1. mysql에서는 문자열과 정수를 비교할 때 문자열은 정수로 형변환이 일어난다.(단, 양쪽 다 '로 둘러싸인 문자열이라면 형태 상관없이 문자열로 취급)

문자열과 정수 비교에서 형변환을 설명하자면, 숫자가 아닌 것들로만 이루어진 문자열을 정수 0으로 취급한다. 또 '123abc' 처럼 숫자로 시작하여 숫자(들)+문자(들)로 구성된 문자열은 연속된 숫자에 해당하는 정수로 취급한다. 여기선 123이 되겠다. 그리고 'abc123'은 'abc123' 그 자체다. 알파벳으로 시작했기 때문이다.
ex) select 'abc' = 0 -> 1 반환
select '1'=1 -> 1 반환.(문자 '1'이 정수 1로 형변환)
select '1abc'=0 -> 0 반환.('1abc'는 1이다.)
select '123a23'=12323 -> 0 반환('123a23'은 숫자로 시작하지만 문자가 중간에 나타났다가 다시 숫자가 등장하므로 문자열 그 자체다. 따라서 '123a23'만 같다고 할 수 있다.)

자세한 건 링크를 참조하길 바란다.
왜 '1'=1 은 1을 반환하는가? :  https://stackoverflow.com/questions/22080382/mysql-why-comparing-a-string-to-0-gives-true

 

mysql: why comparing a 'string' to 0 gives true?

I was doing some MySQL test queries, and realized that comparing a string column with 0 (as a number) gives TRUE! select 'string' = 0 as res; -- res = 1 (true), UNexpected! why!??!?! however, com...

stackoverflow.com

2. pw=('')=0 연산이 왜 앞에서부터 순차적으로 진행되는지 궁금하다면 index(정수)와 id(문자열)로 이루어진 테이블을 하나 만들어서 (0, a), (1, b), (2, c) 데이터를 삽입 후 select id from 테이블명 where index=2=2;를 실행해보면 아무 값도 나오지 않는다는 것을 알 수 있다. 만약 뒤에서부터 비교했다면 2=2 결과 1이 반환되고 index=1인 값이 조회되어야 하는데 index=1인 id는 출력되지 않는다.

728x90

'Lord of SQL Injection' 카테고리의 다른 글

dragon  (0) 2023.01.01
xavis  (2) 2023.01.01
zombie_assassin  (0) 2022.12.23
succubus  (0) 2022.12.23
assassin  (0) 2022.12.23

+ Recent posts