From f4f8c57a74d743fd3cf0ca4f02fcd8658d2b824e Mon Sep 17 00:00:00 2001
From: thisgun
Date: Fri, 8 May 2026 06:22:58 +0000
Subject: [PATCH] =?UTF-8?q?[security]=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?=
=?UTF-8?q?=EC=98=81=EC=97=AD=20=EA=B6=8C=ED=95=9C=20=EA=B2=80=EC=A6=9D=20?=
=?UTF-8?q?=EB=88=84=EB=9D=BD=20=EB=B0=8F=20CSRF=20=ED=86=A0=ED=81=B0=20?=
=?UTF-8?q?=EB=88=84=EB=9D=BD=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- adm/qa_config_update.php / adm/contentformupdate.php :
qa_include_head/tail, co_include_head/tail 가 super 가드 없이 변경 가능해
하위 관리자가 임의 PHP 경로를 include 시킬 수 있던 LFI 위험을
board_form_update.php 와 동일한 패턴(super 외에는 기존 값 유지)으로 차단.
- adm/member_form_update.php / adm/member_list_update.php :
신규 회원 생성·일괄 수정 시 부여하려는 mb_level 상한 검증이 없어
하위 관리자가 자기보다 높은 등급을 부여할 수 있던 권한 상승을 차단.
- adm/shop_admin/categorylistupdate.php /
adm/shop_admin/itemformupdate.php :
is_include_path_check 호출에서 두 번째 인자(is_input=1) 누락으로
rar/php/zip wrapper 등 경로 wrapper 차단이 동작하지 않던 부분을
is_include_path_check($file, 1) 로 강화.
- adm/shop_admin/orderdeliveryupdate.php /
adm/shop_admin/orderpartcancelupdate.php /
adm/sendmail_test.php :
상태 변경 동작에 check_admin_token() 누락으로 발생하던 CSRF 위험을
토큰 검증 추가로 차단. sendmail_test 폼에는 hidden token 필드 추가.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
adm/contentformupdate.php | 11 +++++++++++
adm/member_form_update.php | 5 +++++
adm/member_list_update.php | 2 ++
adm/qa_config_update.php | 6 ++++++
adm/sendmail_test.php | 5 +++++
adm/shop_admin/categorylistupdate.php | 2 +-
adm/shop_admin/itemformupdate.php | 2 +-
adm/shop_admin/orderdeliveryupdate.php | 2 ++
adm/shop_admin/orderpartcancelupdate.php | 2 ++
9 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/adm/contentformupdate.php b/adm/contentformupdate.php
index 61eac97ab..b82c32b3b 100644
--- a/adm/contentformupdate.php
+++ b/adm/contentformupdate.php
@@ -29,6 +29,17 @@ $co_id = isset($_REQUEST['co_id']) ? preg_replace('/[^a-z0-9_]/i', '', $_REQUEST
$co_subject = isset($_POST['co_subject']) ? strip_tags(clean_xss_attributes($_POST['co_subject'])) : '';
$co_include_head = isset($_POST['co_include_head']) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($_POST['co_include_head'], 0, 255)) : '';
$co_include_tail = isset($_POST['co_include_tail']) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($_POST['co_include_tail'], 0, 255)) : '';
+
+// 최고 관리자가 아니면 include 경로 변경 불가 (board_form_update.php 와 동일 정책)
+if ($is_admin !== 'super') {
+ if ($w == 'u') {
+ $co_include_head = isset($co_row['co_include_head']) ? $co_row['co_include_head'] : '';
+ $co_include_tail = isset($co_row['co_include_tail']) ? $co_row['co_include_tail'] : '';
+ } else {
+ $co_include_head = '';
+ $co_include_tail = '';
+ }
+}
$co_tag_filter_use = isset($_POST['co_tag_filter_use']) ? (int) $_POST['co_tag_filter_use'] : 1;
$co_himg_del = (isset($_POST['co_himg_del']) && $_POST['co_himg_del']) ? 1 : 0;
$co_timg_del = (isset($_POST['co_timg_del']) && $_POST['co_timg_del']) ? 1 : 0;
diff --git a/adm/member_form_update.php b/adm/member_form_update.php
index bcc7dc0ac..59c51317d 100644
--- a/adm/member_form_update.php
+++ b/adm/member_form_update.php
@@ -127,6 +127,11 @@ $sql_common = " mb_name = '{$posts['mb_name']}',
mb_9 = '{$posts['mb_9']}',
mb_10 = '{$posts['mb_10']}' ";
+// 부여하려는 mb_level 상한 검증 (자기보다 높은 권한 부여 차단)
+if ($is_admin !== 'super' && (int) $posts['mb_level'] >= (int) $member['mb_level']) {
+ alert('자신보다 권한이 높거나 같은 등급은 부여할 수 없습니다.');
+}
+
if ($w == '') {
$mb = get_member($mb_id);
if (isset($mb['mb_id']) && $mb['mb_id']) {
diff --git a/adm/member_list_update.php b/adm/member_list_update.php
index 0c47e0063..9cfcbeb8f 100644
--- a/adm/member_list_update.php
+++ b/adm/member_list_update.php
@@ -57,6 +57,8 @@ if ($_POST['act_button'] == "선택수정") {
$msg .= $mb['mb_id'] . ' : 회원자료가 존재하지 않습니다.\\n';
} elseif ($is_admin != 'super' && $mb['mb_level'] >= $member['mb_level']) {
$msg .= $mb['mb_id'] . ' : 자신보다 권한이 높거나 같은 회원은 수정할 수 없습니다.\\n';
+ } elseif ($is_admin != 'super' && $post_mb_level >= (int) $member['mb_level']) {
+ $msg .= $mb['mb_id'] . ' : 자신보다 권한이 높거나 같은 등급은 부여할 수 없습니다.\\n';
} elseif ($member['mb_id'] == $mb['mb_id']) {
$msg .= $mb['mb_id'] . ' : 로그인 중인 관리자는 수정 할 수 없습니다.\\n';
} else {
diff --git a/adm/qa_config_update.php b/adm/qa_config_update.php
index 9d604d5d6..6cc313023 100644
--- a/adm/qa_config_update.php
+++ b/adm/qa_config_update.php
@@ -21,6 +21,12 @@ foreach ($check_keys as $key) {
$qa_include_head = isset($qa_include_head) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($qa_include_head, 0, 255)) : '';
$qa_include_tail = isset($qa_include_tail) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($qa_include_tail, 0, 255)) : '';
+// 최고 관리자가 아니면 include 경로 변경 불가 (board_form_update.php 와 동일 정책)
+if ($is_admin !== 'super') {
+ $qa_include_head = isset($qaconfig['qa_include_head']) ? $qaconfig['qa_include_head'] : '';
+ $qa_include_tail = isset($qaconfig['qa_include_tail']) ? $qaconfig['qa_include_tail'] : '';
+}
+
// 관리자가 자동등록방지를 사용해야 할 경우
if ($board && ($qaconfig['qa_include_head'] !== $qa_include_head || $qaconfig['qa_include_tail'] !== $qa_include_tail) && function_exists('get_admin_captcha_by') && get_admin_captcha_by()) {
include_once G5_CAPTCHA_PATH . '/captcha.lib.php';
diff --git a/adm/sendmail_test.php b/adm/sendmail_test.php
index 9cddfbd93..0332d43bd 100644
--- a/adm/sendmail_test.php
+++ b/adm/sendmail_test.php
@@ -9,10 +9,14 @@ if (!$config['cf_email_use'])
include_once(G5_LIB_PATH.'/mailer.lib.php');
+$token = get_token();
+
$g5['title'] = '메일 테스트';
include_once('./admin.head.php');
if (isset($_POST['email'])) {
+ check_admin_token();
+
$_POST['email'] = strip_tags($_POST['email']);
$email = explode(',', $_POST['email']);
@@ -61,6 +65,7 @@ if (isset($_POST['email'])) {