From 5331aa8be5884facf5e65dece1aaf350d73a8b52 Mon Sep 17 00:00:00 2001 From: thisgun Date: Tue, 7 Apr 2026 16:37:39 +0000 Subject: [PATCH] =?UTF-8?q?[security]sql=5Fquery()=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=85=B8=EC=B6=9C=20=EC=8B=9C=20SQL/=EC=8A=A4=ED=82=A4?= =?UTF-8?q?=EB=A7=88=20=EC=A0=95=EB=B3=B4=20=EC=B0=A8=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sql_query()의 에러 처리가 die()로 SQL 쿼리 전문, MySQL 에러 메시지, 스크립트 파일 경로를 사용자에게 그대로 노출하고 있었음. 기본값 G5_DISPLAY_SQL_ERROR=false 덕분에 일반 호출에서는 트리거되지 않으나, 일부 admin 파일이 명시적으로 sql_query(\$sql, true)로 호출하여 관리자에게 raw SQL을 노출했고, SQLi 공격 시도 중 발생한 에러로 DB 구조(테이블/컬럼명)가 학습되어 정밀 공격에 활용될 수 있었음. 조치: - 서버 로그(error_log)에는 항상 상세 기록 → 운영자가 디버깅 가능 - \$is_debug 모드(G5_DEBUG=true 또는 super admin)에서만 상세 표시 + XSS 방지를 위해 htmlspecialchars로 escape - 그 외 환경에서는 "데이터베이스 처리 중 오류가 발생했습니다." 만 표시 - mysqli/mysql 폴백 분기 둘 다 동일하게 적용 변경: - lib/common.lib.php:1932 (mysqli 분기) - lib/common.lib.php:1942 (mysql 분기, 레거시 PHP 5.x 폴백) PHP 5.2.17 호환 유지 (htmlspecialchars + ENT_QUOTES 모두 PHP 4.0+). --- lib/common.lib.php | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/common.lib.php b/lib/common.lib.php index fcd3f4462..af631755d 100644 --- a/lib/common.lib.php +++ b/lib/common.lib.php @@ -1929,7 +1929,24 @@ function sql_query($sql, $error=G5_DISPLAY_SQL_ERROR, $link=null) if(function_exists('mysqli_query') && G5_MYSQLI_USE) { if ($error) { - $result = @mysqli_query($link, $sql) or die("

$sql

" . mysqli_errno($link) . " : " . mysqli_error($link) . "

error file : {$_SERVER['SCRIPT_NAME']}"); + $result = @mysqli_query($link, $sql); + if (!$result) { + $err_no = mysqli_errno($link); + $err_msg = mysqli_error($link); + $err_file = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : ''; + + // 서버 로그에는 항상 상세 기록 (운영자가 추적 가능하도록) + @error_log("[g5 sql_query] {$err_no}: {$err_msg} | SQL: {$sql} | file: {$err_file}"); + + if ($is_debug) { + // 디버그 모드: 상세 표시 (XSS 방지를 위해 escape) + die("

" . htmlspecialchars($sql, ENT_QUOTES, 'UTF-8') + . "

" . (int)$err_no . " : " . htmlspecialchars($err_msg, ENT_QUOTES, 'UTF-8') + . "

error file : " . htmlspecialchars($err_file, ENT_QUOTES, 'UTF-8')); + } + // 운영 환경: 일반 메시지로만 처리하여 DB 구조/경로 정보 노출 방지 + die('데이터베이스 처리 중 오류가 발생했습니다.'); + } } else { try { $result = @mysqli_query($link, $sql); @@ -1939,7 +1956,21 @@ function sql_query($sql, $error=G5_DISPLAY_SQL_ERROR, $link=null) } } else { if ($error) { - $result = @mysql_query($sql, $link) or die("

$sql

" . mysql_errno() . " : " . mysql_error() . "

error file : {$_SERVER['SCRIPT_NAME']}"); + $result = @mysql_query($sql, $link); + if (!$result) { + $err_no = mysql_errno(); + $err_msg = mysql_error(); + $err_file = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : ''; + + @error_log("[g5 sql_query] {$err_no}: {$err_msg} | SQL: {$sql} | file: {$err_file}"); + + if ($is_debug) { + die("

" . htmlspecialchars($sql, ENT_QUOTES, 'UTF-8') + . "

" . (int)$err_no . " : " . htmlspecialchars($err_msg, ENT_QUOTES, 'UTF-8') + . "

error file : " . htmlspecialchars($err_file, ENT_QUOTES, 'UTF-8')); + } + die('데이터베이스 처리 중 오류가 발생했습니다.'); + } } else { $result = @mysql_query($sql, $link); }