해킹당했습니다.

매출이 오르면 내리는 수수료! 지금 수수료센터에서 전자결제(PG)수수료 비교견적 신청해 보세요!
해킹당했습니다.

QA

해킹당했습니다.

본문

1. 그누보드 5.3.3.3 사용중입니다. 

2. 아미나 사용중입니다.

 

서버는 안털린 거 같은데, 관리자 계정이 털렸습니다. 

집 말고 관리자 로그인 한 적 없구요. 

 

<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가

// 세션이 시작되지 않았다면 세션 시작
if (session_status() == PHP_SESSION_NONE) {
    session_start();
}

function admin_access() {
    global $is_admin;

    // 허용된 IP 주소 목록 (IPv4 및 IPv6 포함)
    $allowed_ips = [
        '12.34.56.78', 
    ];

    // 로그 파일 경로
    $log_file = '/var/www/html/admin.log';

    // 현재 사용자 IP
    $user_ip = $_SERVER['REMOTE_ADDR'];

    // 브라우저 정보
    $user_browser = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'Unknown';

    // 로그 기록 함수
    function write_log($message, $log_file) {
        $date = date('Y-m-d H:i:s');
        $log_entry = "[$date] $message\n";
        file_put_contents($log_file, $log_entry, FILE_APPEND | LOCK_EX);
    }

    // 세션 변수 이름 정의
    $session_success_log = 'admin_login_success_logged';
    $session_failure_log = 'admin_login_failure_logged';

    if ($is_admin) {
        // 로그인 성공 로그가 아직 기록되지 않았다면
        if (!isset($_SESSION[$session_success_log])) {
            if (in_array($user_ip, $allowed_ips)) {
                // 어드민 접속 성공 로그
                $message = "LOGIN_SUCCESS - IP: $user_ip - Browser: $user_browser";
                write_log($message, $log_file);
                // 세션에 로그 기록 완료 표시
                $_SESSION[$session_success_log] = true;
            } else {
                // 어드민 접속 실패 로그
                $message = "LOGIN_FAILURE - IP: $user_ip - Browser: $user_browser";
                write_log($message, $log_file);
                // 실패 로그 기록 완료 표시 (필요 시)
                $_SESSION[$session_failure_log] = true;
                exit('비밀번호가 맞지 않습니다.');
            }
        }
    } else {
        // 관리자 권한이 없을 때 (로그인 시도 중일 가능성이 있음)
        // 여기서는 로그인 시도 페이지에서만 로그를 기록하도록 설정할 수 있음
        // 예시: 로그인 페이지일 경우에만 실패 로그 기록
        // 로그인 페이지를 식별하는 조건을 추가해야 함 (예: 특정 GET/POST 파라미터 확인)
        // 아래는 단순 예시입니다.

        // 예를 들어, 로그인 시도 시 'login_attempt' 파라미터가 있을 때만 기록
        if (isset($_POST['login_attempt']) && $_POST['login_attempt'] === '1') {
            // 로그인 실패 로그가 아직 기록되지 않았다면
            if (!isset($_SESSION[$session_failure_log])) {
                $message = "LOGIN_FAILURE - IP: $user_ip - Browser: $user_browser";
                write_log($message, $log_file);
                // 세션에 실패 로그 기록 완료 표시
                $_SESSION[$session_failure_log] = true;
            }
        }
    }
}

// admin_access 함수 호출
admin_access();
?>
 

 

해당 소스 사용해서 등록된 아이피가 아니면 로그인이 안되게도 세팅해뒀습니다. 

 

이유를 모르겠는데, 혹시 경험 많으신분, 짐작가는 이유가 있으신지 궁금합니다.

 

추가로 어디를 봐야하는지 조언 주시면 감사하겠습니다...

 

 

이 질문에 댓글 쓰기 :

답변 5

"""짐작가는 이유가 있으신지 궁금합니다 """

IP 기반 접근 제한을 구현하기 전에 또는 코드가 작동하지 않았을 때,

공격자가 관리자 계정에 접근했을 수 있으며,

또한 권한 설정이 잘못되어 관리자 계정 정보가 포함된 설정 파일이나

세션 정보가 노출 되었을 수 있으며,

그누보드의 구조는 익히 알려져 있기에,

'IP 스푸핑'이나 'brute force' 공격을 당했을 가능성도 있습니다.

 

세션 로그아웃 이나 비밀번호 변경은 하셨을 것같고,

현재 IP 제한 코드의 정상 동작 여부를 확인하셨나요?

- 관리자 계정이 아닌 상태에서, 허용되지 않은 IP에서 관리자 페이지에 접속을 시도,

- 서버가 파일 캐시를 사용하는 경우, IP 제한 코드가 반영되지 않았을 가능성이 있으니,

  서버 캐시를 삭제하거나 재시작,

- IPv4와 IPv6 환경이 샤용되는 경우,

  코드가 IPv6 주소를 제대로 처리하지 못할 수 있으니, IPv6 주소도 테스트 등을 하여 보세요.

 

 

♠ 해결 방안

 

*관리자 경로를 예측하기 어려운 이름으로 변경(예: /admin-asdgshrtjkk345678wrg).

*.htaccess(apache) 또는 서버 설정에서 특정 IP만 관리자 페이지에 접근할 수 있도록 제한.


<Directory "/path/to/admin">
    Require ip 12.34.56.78
</Directory>

 

★ 아래는 관리자 페이지 접근, brute force 공격 등에 대응하여 

  제시하신 소스를 수정한 예시입니다.


<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
if (session_status() == PHP_SESSION_NONE) {
    session_start();
}
define('ADMIN_LOG_FILE', '/var/log/admin_access.log');
define('FAILED_ATTEMPTS_FILE', '/var/log/failed_attempts.json');
define('MAX_LOGIN_ATTEMPTS', 5);
define('BLOCK_DURATION', 3600); // 차단 시간 (1시간)
// IP 검증 함수 (CIDR 지원)
function ip_in_allowed_range($ip, $allowed_ips) {
    foreach ($allowed_ips as $allowed_ip) {
        if (strpos($allowed_ip, '/') === false) {
            // 단일 IP 비교
            if ($ip === $allowed_ip) return true;
        } else {
            // CIDR 대역 비교
            [$subnet, $bits] = explode('/', $allowed_ip);
            $subnet_binary = ip2long($subnet);
            $ip_binary = ip2long($ip);
            $mask = -1 << (32 - $bits);
            if (($ip_binary & $mask) === ($subnet_binary & $mask)) return true;
        }
    }
    return false;
}
// 로그 기록 함수
function write_log($message) {
    $date = date('Y-m-d H:i:s');
    $log_entry = "[$date] $message\n";
    file_put_contents(ADMIN_LOG_FILE, $log_entry, FILE_APPEND | LOCK_EX);
}
// 실패 시도 기록 및 차단 처리
function block_ip($ip) {
    $failed_attempts = is_file(FAILED_ATTEMPTS_FILE) ? json_decode(file_get_contents(FAILED_ATTEMPTS_FILE), true) : [];
    $current_time = time();
    if (!isset($failed_attempts[$ip])) {
        $failed_attempts[$ip] = ['count' => 0, 'last_attempt' => $current_time];
    }
    $failed_attempts[$ip]['count']++;
    $failed_attempts[$ip]['last_attempt'] = $current_time;
    // 차단 처리
    if ($failed_attempts[$ip]['count'] > MAX_LOGIN_ATTEMPTS && ($current_time - $failed_attempts[$ip]['last_attempt'] < BLOCK_DURATION)) {
        exit('Your IP has been temporarily blocked.');
    }
    file_put_contents(FAILED_ATTEMPTS_FILE, json_encode($failed_attempts));
}
// 관리자 접근 제한 함수
function admin_access() {
    global $is_admin;
    $allowed_ips = [
        '12.34.56.78',       // 단일 IP
        '192.168.1.0/24',    // CIDR 대역
    ];
    $user_ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'];
    $user_browser = $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown';
    $session_success_log = 'admin_login_success_logged_' . $user_ip;
    // 실패 시도 감지 및 차단
    block_ip($user_ip);
    if ($is_admin && ip_in_allowed_range($user_ip, $allowed_ips)) {
        // 세션 IP 바인딩
        if (!isset($_SESSION['user_ip'])) {
            $_SESSION['user_ip'] = $user_ip;
        } elseif ($_SESSION['user_ip'] !== $user_ip) {
            session_destroy();
            exit('Session invalid due to IP mismatch.');
        }
        // 성공 로그
        if (!isset($_SESSION[$session_success_log])) {
            $message = "LOGIN_SUCCESS - IP: $user_ip - Browser: $user_browser";
            write_log($message);
            $_SESSION[$session_success_log] = true;
        }
    } else {
        // 실패 로그
        $request_method = $_SERVER['REQUEST_METHOD'];
        $request_uri = $_SERVER['REQUEST_URI'];
        $message = "LOGIN_FAILURE - IP: $user_ip - Browser: $user_browser - Method: $request_method - URI: $request_uri";
        write_log($message);
        // 차단 처리
        block_ip($user_ip);
        exit('Unauthorized access.');
    }
}
// admin_access 함수 호출
admin_access();
?>

 

 

1. 관리자 계정이 털렸다는 건 어떻게 아신건지요 ?
 $log_file = '/var/www/html/admin.log'; 에서 확인하셨나요?

아니면, 저기에는 아무런 내용이 없는 건가요 ?

 

만약 저기에 내용이 기록이 되어있다면, 아이피 + 2차 인증 같은걸 고민해보셔야 합니다.

그래야 조금 더 보안적으로 좋을 듯 합니다. 

 

그렇지만, 저기에 기록이 없다면... ? 무슨 내용을 확인하신 건지 조금 궁금하네요

 

 

2. 최신 버전이 아니네요 항상 최신 버전을 유지하시는 게 좋습니다.

1. 관리자 계정 자체로 글 작성은 되었지만, 저기 로그 기록에는 없다면, 여러가지를 고려해야 할 것 같습니다

그 단적인 예로 애초에 로그인이 막혔는데 글이 등록되었다면,
글 등록 관련을 조사(?)해야 할 것 같구요

mysql 같은 디비 비밀번호가 열린 건 아닌지 확인해보셔야 합니다.
혹시라도 서버에 비정상적인 파일이 없는지 새롭게 추가된 파일은 없는지도 한번 확인해보세요

2. 아미나 사용자가 아니라 정확한 답변은 아니지만, 애초에 "그누보드 기반"이라서, 그누보드 업데이트 부분만 패치 하면 될텐데요 ?

그누보드로는 해킹방어에 구조상 한계가 있습니다.

특히나, 플러그인 및 공개되어 있는 소스들의 짜집기라면...

그중 하나는 비집고 해킹할 부분이 존재한다고 봐야겠죠.

전문가와 상의하세요.

관리자 계정이 털렸다는게

타 아이디로 관리자 권한 탈취 인가요.

아니면 순수 관리자 계정이 털렸다는건가요?

명확하게 현재 상황을 적어주셔야 합니다.

 

후자라면 

$is_admin 변수로 하지 마시고 $member['mb_level'] 로 채크 하세요.

패스워드는 가급적 길게 영문 숫자 특수문자 조합으로 재설정 하시구요

 

그리고 해당 PC 가 털린건 아닌지도 채크해보시구요

답변을 작성하시기 전에 로그인 해주세요.
전체 0
QA 내용 검색

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT