๋ฌธ์ : DreamHack โ [CodeEngn] Malware L05 ๋ถ๋ฅ: Misc (์ ์ฑ์ฝ๋ ์์ค ๋ถ์) ๋์ด๋: ๐ฅ Bronze 1 FLAG:
base64
๋ฐฐํฌ ํ์ผ์ ํ ์คํธ ํ ์ฅ์ด๊ณ ๋ฌธ์ ์ค๋ช ์ ๋ ์ค์ด๋ค. ํํธ๋ ์๋ค.
# show_desc.sh
#!/bin/sh
# show_desc.sh โ ๋๋ฆผํต API ์์ ์ด ๋ฌธ์ ์ ์ ๋ชฉยท๋ถ๋ฅยท์ค๋ช
๋ง ๋ฝ์ ๋ณธ๋ค
python3 ~/Dev/Hacking_Project/_๋๊ตฌ/dreamhack_auto/fetch_desc.py 372 | python3 -c '
import sys, json
d = json.load(sys.stdin)
print("์ ๋ชฉ :", d["title"].strip())
print("๋ถ๋ฅ :", ", ".join(d["tags"]))
print("๋์ด๋ :", d["tier_display"])
print("ํผ ์ฌ๋ :", d["cnt_solvers"], "๋ช
")
print()
print("[๋ฌธ์ ์ค๋ช
]")
print(d["description"].strip())
print()
print("[ํํธ]", d["hints"] or "์์")
'./show_desc.sh
์ ๋ต์ ์๋ฌธ์ ํ ๋จ์ด, ๋์ด์ฐ๊ธฐ ์์ด. ๊ฐ์ ์๋ฆฌ์ฆ Malware L02๊ฐ webdav, Malware L03์ด checksum ์ด์์ผ๋ ํ์์ ๊ทธ๋๋ก๋ค.
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | [CodeEngn] Malware L05 (DreamHack #372) |
| ๋์ด๋ | ๐ฅ Bronze 1 |
| ๋ถ๋ฅ | Misc โ ์ ์ฑ์ฝ๋ ์์ค ๋ถ์ |
| ๋ฐฐํฌ๋ฌผ | 05.txt 566๋ฐ์ดํธ, 31์ค (CRLF) |
| ์๊ตฌ ๋ต์ | ์๋ฌธ์ ํ ๋จ์ด, ๋์ด์ฐ๊ธฐ ์์ |
| ํต์ฌ | ์ํ๋ฒณ 64์ + 6๋นํธ ๋ง์คํฌ + 76์ด CRLF ์ ๊ธฐ |
๋ฐ์ท๋ณธ์ ๋ณด๋ฉด 3์ด ๋ง์ "base64๊ฒ ๋ค" ์๋ฆฌ๊ฐ ๋์จ๋ค. ๊ทธ๋ฐ๋ฐ ๊ทธ ๊ฐ์ด ๋ง๋์ง๋ ๋ณ๊ฐ ๋ฌธ์ ๋ค.
Malware L03์์ ๋ชจ์๋ง ๋ณด๊ณ crc ๋ก ๊ฐ ๋ปํ๋ ์ ์ด ์์ด์, ์ด๋ฒ์๋ ์์๋ฅผ ๋๊ฐ์ด ์ก์๋ค โ ๊ฐ๋ ค์ง ๋ถ๋ถ์ ์ฑ์ ์ค์ ๋ก ์ปดํ์ผํ๊ณ , ํ์ค ๊ตฌํ๊ณผ ๋ฐ์ดํธ ๋จ์๋ก ๋ง์ถฐ ๋ณด๊ณ , ์ 3์ ๋๊ตฌ๊ฐ ๊ทธ ์ถ๋ ฅ์ ๋๋๋ฆฌ๋์ง ํ์ธํ๋ค.
ํ์ด ํ๋ฆ์ ์ด๋ ๋ค. ๋ฐฐํฌ๋ณธ ์ ์ฐฐ โ ์ํ๋ฒณ ๋์กฐ โ ๊ฐ๋ ค์ง ๋ ์ค ๋ณต์ โ ์ปดํ์ผ โ ์ ์ ยท๋ฐํ์ ํ์ธ โ ํ์ค base64 ์ ์ ์ ๋์กฐ โ ๋ฉ์ผ ํ์์ ๋จน์ฌ ๋ณด๊ธฐ.
๐งฉ ๋ฐฐ๊ฒฝ โ ์ ์ฑ์ฝ๋๊ฐ base64 ๋ฅผ ํ๊ณ ๋ค๋๋ ์ด์
SMTP ๋ ํ์์ด 7๋นํธ ํ
์คํธ ํ๋กํ ์ฝ์ด๋ค. ๋ฉ์ผ ๋ณธ๋ฌธ์ ๋ฐ์ด๋๋ฆฌ๋ฅผ ๊ทธ๋๋ก ์ค์ผ๋ฉด ์ค๊ฐ ์๋ฒ๊ฐ 8๋ฒ์งธ ๋นํธ๋ฅผ ๋ ๋ฆฌ๊ฑฐ๋, CR/LF/. ๊ฐ์ ๋ฐ์ดํธ๋ฅผ ํ๋กํ ์ฝ ์ ์ด๋ก ์คํดํ๋ค. ๊ทธ๋์ ์ฒจ๋ถํ์ผ์ ๋ฐ๋์ ์์ ํ ๋ฌธ์ ์งํฉ์ผ๋ก ๋ฐ๊ฟ์ ์ค์ด์ผ ํ๋ค.
๊ทธ ๊ท๊ฒฉ์ด RFC 2045 MIME ์ด๊ณ , ๊ทธ ์์ Content-Transfer-Encoding: base64 ๊ฐ ์ด ๋ฌธ์ ์ ๋ฌด๋๋ค.
๊ฐ์ CodeEngn ์๋ฆฌ์ฆ์ Malware L06ยทMalware L07์ด SMTP ์์ปค ์ค๋ ๋๋ฅผ ๋์ฐ๋ ๋ค์ด๋ก๋๋ฅผ ๋ค๋ฃฌ๋ค. ์ด ๋ฐ์ท๋ณธ์ด ์ ํํ ์ด๋ ์ํ์์ ๋์๋์ง๋ ๋ฌธ์ ๊ฐ ๋ฐํ์ง ์์ง๋ง, 76์ด ์ ๊ธฐ๋ MIME ๋ง๊ณ ๋ ์ธ ๋ฐ๊ฐ ์๋ ๊ท๊ฒฉ์ด๋ผ ์ฉ๋๋ ๋ฉ์ผ ๋ณธ๋ฌธยท์ฒจ๋ถ๋ก ์ขํ์ง๋ค.
๊ท๊ฒฉ ์๋ฌธ์ ์ง์ ํ์ธํด ๋๋ฉด ๋ค์์ ์ซ์๋ฅผ ๋์กฐํ ๋ ๊ทผ๊ฑฐ๊ฐ ์๊ธด๋ค.
# rfc_evidence.sh
#!/bin/sh
# rfc_evidence.sh โ 76์ดยทํจ๋ฉ ๊ท์ ์ด ์ด๋ ๋ฌธ์์์ ์ค๋์ง ์๋ฌธ์ผ๋ก ํ์ธ
# ๋ฌธ์: curl -sS -o rfc2045.txt https://www.rfc-editor.org/rfc/rfc2045.txt
echo "rfc2045.txt = $(wc -c < rfc2045.txt) B / $(wc -l < rfc2045.txt) ์ค"
echo
echo '--- 6.8 ์ ์ ๋ชฉ ---'
sed -n '1295,1297p' rfc2045.txt
echo
echo '--- ์ค ๊ธธ์ด ๊ท์ ---'
sed -n '1372,1374p' rfc2045.txt
echo
echo '--- ํจ๋ฉ ๊ท์ (๋ฐฐํฌ๋ณธ์ ์๋ ๋ถ๋ถ) ---'
sed -n '1380,1385p' rfc2045.txtsh rfc_evidence.sh
๋ ๋ฌธ์ฅ์ด ๋ค์์ ๊ทธ๋๋ก ์ฐ์ธ๋ค. "์ถ๋ ฅ์ ํ ์ค์ 76์๋ฅผ ๋์ง ์๋๋ค"์ "๋์ด 24๋นํธ์ ๋ชป ๋ฏธ์น๋ฉด = ๋ก ์ฑ์ด๋ค". ๋ฐฐํฌ๋ณธ์ ์์ ๊ฒ๋ง ํ๋ด ๋ด๊ณ ๋ค์ ๊ฒ์ ์์ ์๋ค.
๐ฌ ์ฝ๋ ์ ์ฐฐ โ ๋ฌด์์ด ์ฃผ์ด์ก๋
๋จผ์ ๋ฐฐํฌ๋ฌผ์ด ๋ช ์ค์ด๊ณ ์ด๋๊ฐ ๊ฐ๋ ค์ก๋์ง๋ถํฐ ์ผ๋ค.
# recon.sh
#!/bin/sh
# recon.sh โ ๋ฐฐํฌ๋ณธ ์ ์ฐฐ: ๋ฌด์์ด ๋ค์ด ์๊ณ ์ค๋์ด ๋ฌด์์ธ๊ฐ
ls -l extracted/
file extracted/05.txt
wc -lc extracted/05.txt
echo '--- ์ 5์ค (cat -A ๋ก ์ค๋๊น์ง) ---'
head -5 extracted/05.txt | cat -A
echo '--- ๊ฐ๋ ค์ง ๋ถ๋ถ "..." ์ด ๋ช ๊ตฐ๋ฐ์ธ๊ฐ ---'
grep -n '\.\.\.' extracted/05.txtsh recon.sh
566๋ฐ์ดํธ 31์ค. ๊ฐ๋ ค์ง ๊ณณ์ 8๋ฒ ์ค๊ณผ 28๋ฒ ์ค ๋ ๊ตฐ๋ฐ๋ค. ์ ๋ฌธ์ ์ด๋ ๋ค.
int Malware_L05(char *StartOfData,char *Output,int SizeOfData)
{
int encoded=0,i,l=0;
char Table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
long buffer,buffer2;
do
{
...
for(i=3;i>=0;i--,l++)
{
buffer2=buffer;
buffer2 &= 0x3f;
*(Output + i)=Table[buffer2];
buffer>>=6;
}
Output+=4;
encoded+=4;
SizeOfData-=3;
if(l==76 && SizeOfData>3)
{
*Output=0xd;
Output++;
*Output=0xa;
Output++;
encoded+=2;
l=0;
}
...
}while(SizeOfData!=0);
return encoded;
}ํ ๋ฐํด์ ์
๋ ฅ์ด 3 ์ค๊ณ (SizeOfData-=3) ์ถ๋ ฅ์ด 4 ๋๋ค(Output+=4). 0x3f ๋ง์คํฌ๋ 6๋นํธ๋ค. 8ร3 = 24 = 6ร4 ์ด๋ ๋นํธ ์๊ฐ ์ ํํ ๋ง๋๋ค.
์ํ๋ฒณ์ด ์ง์ง ํ์ค์ธ์ง๋ ๋์ผ๋ก ์ธ์ง ๋ง๊ณ ์ธ๋ฑ์ค๋ณ๋ก ๋ง์ถฐ ๋ณธ๋ค. ๋ฌธ์์ด์ ์์ผ๋ก ์ฎ๊ฒจ ์ ์ผ๋ฉด ๊ทธ ์์ฒด๊ฐ ์ค์ฐจ์์ด๋ผ, ๋ฐฐํฌ๋ณธ์์ ์ ๊ท์์ผ๋ก ๊ธ์ด ์ด๋ค.
#!/usr/bin/env python3
"""table_check.py โ ๋ฐฐํฌ๋ณธ์ Table[] ์ด RFC 4648 ํ์ค ์ํ๋ฒณ์ธ์ง ์ธ๋ฑ์ค๋ณ๋ก ๋์กฐ.
๋ฐฐํฌ๋ณธ์์ ๋ฌธ์์ด ๋ฆฌํฐ๋ด์ ์ง์ ๊ธ์ด ์ด๋ค(์์ผ๋ก ์ฎ๊ฒจ ์ ์ง ์๋๋ค).
"""
import re
import string
src = open("extracted/05.txt", "rb").read().decode("ascii")
m = re.search(r'char\s+Table\[\]\s*=\s*"([^"]*)"', src)
table = m.group(1)
rfc4648 = string.ascii_uppercase + string.ascii_lowercase + string.digits + "+/"
print(f"๋ฐฐํฌ๋ณธ Table[] ๊ธธ์ด : {len(table)}")
print(f"RFC 4648 Table 1 : {len(rfc4648)}")
print(f"์ ์ฒด ์ผ์น : {table == rfc4648}")
print(f"ํจ๋ฉ๋ฌธ์ '=' ํฌํจ : {'=' in table}")
diff = [(i, a, b) for i, (a, b) in enumerate(zip(table, rfc4648)) if a != b]
print(f"์ธ๋ฑ์ค๋ณ ๋ถ์ผ์น : {len(diff)}๊ฑด")
print("\n idx chr | idx chr | idx chr | idx chr")
for r in range(16):
row = []
for c in range(4):
i = r + 16 * c
row.append(f" {i:3d} '{table[i]}' ")
print("|".join(row))python3 table_check.py
64์ ์ ๋ถ ์ผ์นํ๊ณ ๋ถ์ผ์น๋ 0๊ฑด์ด๋ค. ์ปค์คํ ์ํ๋ฒณ์ผ๋ก ๋นํผ ๋ณ์ข ์ด ์๋๋ผ ํ์ค ๊ทธ๋๋ก๋ค.
ํ ๊ฐ์ง ๋ ๋์ ๊ฑธ๋ฆฌ๋ ๊ฑด = ๊ฐ ์๋ค๋ ์ ์ด๋ค. RFC 2045 ๊ฐ ์๊ตฌํ๋ ํจ๋ฉ ๋ฌธ์๊ฐ ํ
์ด๋ธ์ ์์ ์์ผ๋, ์ด ๊ตฌํ์ 3์ ๋ฐฐ์๊ฐ ์๋ ์
๋ ฅ์ ์ฒ๋ฆฌํ ๋ฐฉ๋ฒ์ด ์์ฒ์ ์ผ๋ก ์๋ค. ๋ค์์ ์ค์ ๋ก ํ์ธํ๋ค.
๐งฑ ๊ฐ๋ ค์ง ๋ ์ค์ ์ฌ์ค ์ ํด์ ธ ์๋ค
... ๋ฅผ ์๋ฌด ์ฝ๋๋ก๋ ์ฑ์ธ ์ ์๋ ๊ฒ ์๋๋ค. ๋ณด์ด๋ for ๋ฃจํ๊ฐ ์ด๋ฏธ ๋ต์ ๊ฐ์ ํ๋ค.
for(i=3;i>=0;i--,l++)
{
buffer2=buffer;
buffer2 &= 0x3f;
*(Output + i)=Table[buffer2];
buffer>>=6;
}i ๊ฐ 3์์ 0์ผ๋ก ๋ด๋ ค๊ฐ๋ฉด์ ๋งค๋ฒ buffer ์ ํ์ 6๋นํธ๋ฅผ ๊บผ๋ธ๋ค. ๊ทธ๋ฌ๋๊น Output[3] ์๋ buffer ์ ๋นํธ 5..0 ์ด, Output[0] ์๋ ๋นํธ 23..18 ์ด ๋ค์ด๊ฐ๋ค. ์ถ๋ ฅ ์ฒซ ๊ธ์๊ฐ ์
๋ ฅ ์ฒซ ๋ฐ์ดํธ์ ์์ 6๋นํธ๊ฐ ๋๋ ค๋ฉด buffer ๋ byte0<<16 | byte1<<8 | byte2 ์ฌ์ผ ํ๋ค.
๋ฐ๋๋ก ์ฑ์ฐ๋ฉด ๊ฒฐ๊ณผ๊ฐ ํต์งธ๋ก ๋ฌ๋ผ์ง๋ค. ์ฆ 8๋ฒ ์ค์ 3๋ฐ์ดํธ๋ฅผ ๋น
์๋์ธ์ผ๋ก ์ ์ฌํ๋ ์ฝ๋๊ณ , 28๋ฒ ์ค์ ์
๋ ฅ ํฌ์ธํฐ๋ฅผ 3 ์ ์ง์ํค๋ ์ฝ๋๋ค(๋ค๋ฅธ ์ด๋์์๋ StartOfData ๊ฐ ์ ์์ง์ธ๋ค).

์ด ๋ ผ๋ฆฌ๋๋ก ์ฑ์ด ์ฌ๊ตฌ์ฑ๋ณธ์ด๋ค. ๊ฐ๋ ค์ง์ง ์์ ์ค์ ๊ณต๋ฐฑยทํญ๊น์ง ๋ฐฐํฌ๋ณธ ๊ทธ๋๋ก ๋๊ณ ๋ ๊ณณ๋ง ๋ฃ์๋ค. ๋ฐ๋ ์์๋ก ์ ์ฌํ๋ ๋์กฐ๊ตฐ๋ ๊ฐ์ ํ์ผ์์ ๋ง๋ค ์ ์๊ฒ ๋งคํฌ๋ก๋ก ๊ฐ๋ผ ๋๋ค.
/* snippet.c โ DreamHack #372 [CodeEngn] Malware L05 ๋ฐฐํฌ๋ณธ ์ฌ๊ตฌ์ฑ
*
* ๋ฐฐํฌ๋ณธ extracted/05.txt ๋ ํจ์ ๋ณธ๋ฌธ ๋ ๊ณณ์ด "..." ๋ก ๊ฐ๋ ค์ ธ ์๋ค.
* ๊ฐ๋ ค์ง์ง ์์ ์ค์ ๊ณต๋ฐฑ/ํญ๊น์ง ๊ทธ๋๋ก ๋๊ณ , "..." ๋ ๊ณณ๋ง ์ฑ์ ๋ค.
* (A) do { ์งํ โ ์
๋ ฅ 3๋ฐ์ดํธ๋ฅผ buffer ๋ก ์ ์ฌ
* (B) l=0; } ๋ค โ ์
๋ ฅ ํฌ์ธํฐ ์ ์ง
* ๋ฌด์์ ์ฑ์์ผ ํ๋์ง๋ ์๋ for ๋ฃจํ๊ฐ ์ด๋ฏธ ๊ฒฐ์ ํ๋ค.
*
* LOAD_LITTLE_ENDIAN ์ ์ ์ํด ๋น๋ํ๋ฉด (A)๋ฅผ ๋ฐ๋ ๋ฐ์ดํธ์์๋ก ์ฑ์ด
* ๋์กฐ๊ตฐ์ด ๋ง๋ค์ด์ง๋ค โ ์ค๋
๋ณํ์ด base64 ๊ฐ ์๋์ ๋ณด์ด๋ ์ฉ๋.
*/
#include "snippet.h"
int Malware_L05(char *StartOfData,char *Output,int SizeOfData)
{
int encoded=0,i,l=0;
char Table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
long buffer,buffer2;
do
{
/* ---- (A) ๊ฐ๋ ค์ง ๋ถ๋ถ: 3๋ฐ์ดํธ ์ ์ฌ ---- */
#ifdef LOAD_LITTLE_ENDIAN
buffer = (long)(unsigned char)StartOfData[2] << 16
| (long)(unsigned char)StartOfData[1] << 8
| (long)(unsigned char)StartOfData[0];
#else
buffer = (long)(unsigned char)StartOfData[0] << 16
| (long)(unsigned char)StartOfData[1] << 8
| (long)(unsigned char)StartOfData[2];
#endif
/* --------------------------------------- */
for(i=3;i>=0;i--,l++)
{
buffer2=buffer;
buffer2 &= 0x3f;
*(Output + i)=Table[buffer2];
buffer>>=6;
}
Output+=4;
encoded+=4;
SizeOfData-=3;
if(l==76 && SizeOfData>3)
{
*Output=0xd;
Output++;
*Output=0xa;
Output++;
encoded+=2;
l=0;
}
/* ---- (B) ๊ฐ๋ ค์ง ๋ถ๋ถ: ์
๋ ฅ ํฌ์ธํฐ ์ ์ง ---- */
StartOfData+=3;
/* ------------------------------------------- */
}while(SizeOfData!=0);
return encoded;
}๊ตฌ๋๊ธฐ๋ ์ต์ํ์ผ๋ก ์งฐ๋ค. ํ์ค์ ๋ ฅ์ ํต์งธ๋ก ์ฝ์ด ๋๊ธฐ๊ณ ๋ฐํ๊ฐ๋งํผ ํ์ค์ถ๋ ฅ์ผ๋ก ํ๋ฆฐ๋ค. ๋ฐํ๊ฐ ์์ฒด๋ ํ์ค์๋ฌ๋ก ๋นผ์ ์ถ๋ ฅ ๋ฐ์ดํธ์ด์ ์ค์ผ์ํค์ง ์๋๋ค.
/* driver.c โ ๋ฐฐํฌ๋ณธ ํจ์๋ฅผ ๊ทธ๋๋ก ํธ์ถํ๋ ์ต์ ๊ตฌ๋๊ธฐ.
* stdin ์ ๋ฐ์ดํธ ์ ๋ถ๋ฅผ StartOfData ๋ก, ๊ฒฐ๊ณผ๋ฅผ stdout ์ผ๋ก ๊ทธ๋๋ก ํ๋ฆฐ๋ค.
* ๋ฐํ๊ฐ(encoded)์ stderr ์ "encoded=N" ์ผ๋ก ์ฐ๋๋ค โ stdout ์ ์ค์ผ์ํค์ง ์๋๋ค.
* ์ฌ์ฉ: ./l05 < ์
๋ ฅํ์ผ > ์ถ๋ ฅํ์ผ
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "snippet.h"
int main(void)
{
static char in[1 << 20];
size_t n = 0, r;
while ((r = fread(in + n, 1, sizeof(in) - n, stdin)) > 0) n += r;
/* 4/3 ๋ฐฐ + 76์ด๋ง๋ค CRLF 2๋ฐ์ดํธ + ๋๋ํ ์ฌ์ */
size_t cap = n * 2 + 4096;
char *out = calloc(1, cap);
if (!out) return 2;
int encoded = Malware_L05(in, out, (int)n);
fwrite(out, 1, (size_t)encoded, stdout);
fprintf(stderr, "encoded=%d\n", encoded);
return 0;
}๋น๋ํ๊ณ 3๋ฐ์ดํธ ํ๋๋ง ๋จน์ฌ ๋ณธ๋ค. ์
๋ ฅ์ base64 ์์ ๋ก ๊ด์ฉ์ ์ผ๋ก ์ฐ๋ Man ์ด๋ค.
# firstrun.sh
#!/bin/sh
# firstrun.sh โ ์ฌ๊ตฌ์ฑ๋ณธ ๋น๋ ํ 3๋ฐ์ดํธ ํ๋๋ก ์ต์ ๊ฒ์ฆ
gcc -O0 -g -Wall -o l05 driver.c snippet.c && echo 'BUILD OK'
printf 'Man' > t3.bin
echo '--- ๋ฐฐํฌ๋ณธ ํจ์์ ์ถ๋ ฅ ---'
./l05 < t3.bin | xxd
echo '--- coreutils base64 ์ ์ถ๋ ฅ ---'
base64 -w0 < t3.bin; echosh firstrun.sh
TWFu ๋ก ๊ฐ๋ค. ์์์ ์ ์กํ๋ค.
๐ ๏ธ ์ ์ ๋ถ์ โ ์ปดํ์ผ๋ ์ฝ๋๊ฐ ๋ญ ํ๋์ง ๋ณธ๋ค
์์ค๋ง ์ฝ๊ณ ๋์ด๊ฐ๋ฉด "๋ด๊ฐ ์ฑ์ด ์ฝ๋๊ฐ ๋ง๋ค"๋ ์ํ๋ ผ์ฆ์ด ๋๋ค. ์ปดํ์ผ ๊ฒฐ๊ณผ๋ฅผ ๋ฏ์ด ๋ณด๋ฉด ๋ฐ์ท๋ณธ์ ์ค์ ๋ก ์๋ ์ฐ์ฐ์ด ์ด๋ค ๋ช ๋ น์ผ๋ก ๋จ์ด์ง๋์ง๊ฐ ๋์ ๋ณด์ธ๋ค.
๋์ค์ด์
๋ธ ์ถ๋ ฅ์ ์ฃผ์์ ์น๋๋ฐ, --cmd ์์ sed ์นํ์์ ์ธ๋ผ์ธ์ผ๋ก ๋ฃ์ผ๋ฉด ๋ฐ์ดํ๊ฐ ๊นจ์ง๋ฏ๋ก ๊ท์น ํ์ผ์ ๋ฐ๋ก ๋๋ค.
s|shl rax,0x10|& <-- byte0 << 16|
s|shl rax,0x8|& <-- byte1 << 8|
s|and QWORD PTR \[rbp-0x58\],0x3f|& <-- buffer2 \&= 0x3f : ํ์ 6๋นํธ๋ง|
s|sar QWORD PTR \[rbp-0x60\],0x6|& <-- buffer >>= 6 : ๋ค์ 6๋นํธ๋ก|
s|sub DWORD PTR \[rbp-0x84\],0x3|& <-- SizeOfData -= 3 : 3๋ฐ์ดํธ ์๋น|
s|cmp DWORD PTR \[rbp-0x64\],0x4c|& <-- l == 76 : MIME ํ ์ค ์ํ|
s|cmp DWORD PTR \[rbp-0x84\],0x3|& <-- SizeOfData > 3 : ๋ง์ง๋ง ๊ทธ๋ฃน์ด๋ฉด ์ ๊ธฐ ์๋ต|
s|mov BYTE PTR \[rax\],0xd|& <-- 0x0d CR|
s|mov BYTE PTR \[rax\],0xa|& <-- 0x0a LF|
s|cmp DWORD PTR \[rbp-0x84\],0x0|& <-- SizeOfData != 0 : ">0" ์ด ์๋๋ค|# disasm.sh
#!/bin/sh
# disasm.sh โ Malware_L05 ๋์ค์ด์
๋ธ ๋ฐ์ท + annotate.sed ์ฃผ์
# ์ฌ์ฉ: sh disasm.sh <์์์ค> <๋์ค> (ํจ์ ์ฒซ ์ค์ด 1)
objdump -d --no-show-raw-insn -M intel l05 \
| sed -n '/<Malware_L05>:/,/^$/p' \
| sed -n "${1:-1},${2:-200}p" \
| sed -f annotate.sedsh disasm.sh 30 66
shl rax,0x10 ๊ณผ shl rax,0x8 ์ด ์์๋๋ก ๋์ค๊ณ ๊ทธ ์ฌ์ด์ ์
๋ ฅ ํฌ์ธํฐ๊ฐ +0x1, +0x2 ๋ก ์์ง์ธ๋ค. ์ฒซ ๋ฐ์ดํธ๊ฐ 16๋นํธ ์ผ์ชฝ์ผ๋ก ๋ฐ๋ฆฐ๋ค๋ ๊ฑด ๋น
์๋์ธ ์ ์ฌ๋ผ๋ ๋ป์ด๋ค. ๋ฃจํ ์์ and ...,0x3f โ ํ
์ด๋ธ ์ธ๋ฑ์ฑ โ sar ...,0x6 ์ธ ๋ฐ์๋ค.
์ฌ๊ธฐ์ ํ๋ ๋ ๋์ฌ๊ฒจ๋ณผ ๊ฒ ์๋ค. ์ํ๋ฒณ์ด ๋ฌธ์์ด ํ ์ด๋ธ์ ์ ๋จ๋๋ค.
# strings_probe.sh
#!/bin/sh
# strings_probe.sh โ base64 ์ํ๋ฒณ์ด ๋ฌธ์์ด ํ
์ด๋ธ์ ๋จ๋๊ฐ
echo '--- strings ๋ก ์ํ๋ฒณ ์ฐพ๊ธฐ (๋งค์น ์) ---'
strings -a l05 | grep -c 'ABCDEFGHIJKLMNOP'
echo '--- .rodata ์ ์ฒด ---'
objdump -s -j .rodata l05 | tail -4
echo '--- ์ํ๋ฒณ์ movabs ์ฆ์น๊ฐ 8๊ฐ๋ก ์คํ์ ๊น๋ฆฐ๋ค ---'
objdump -d --no-show-raw-insn -M intel l05 | grep 'movabs'
echo '--- ์ฆ์น๊ฐ์ ๋ฆฌํ์๋์ธ์ผ๋ก ๋๋๋ฆฌ๋ฉด ---'
python3 -c "import struct,sys; print(b''.join(struct.pack('<Q',int(x,16)) for x in sys.argv[1:]).decode())" \
0x4847464544434241 0x504f4e4d4c4b4a49 0x5857565554535251 0x6665646362615a59 \
0x6e6d6c6b6a696867 0x767574737271706f 0x333231307a797877 0x2f2b393837363534sh strings_probe.sh
char Table[] ์ด ์ง์ญ ๋ฐฐ์ด์ด๋ผ ์ปดํ์ผ๋ฌ๊ฐ .rodata ์ ๋์ง ์๊ณ movabs ์ฆ์น๊ฐ 8๊ฐ๋ก ์คํ์ ๊น์ ๋ฒ๋ฆฐ๋ค. ๊ทธ๋์ strings ๋ก๋ 0๊ฑด์ด๋ค. ์ค์ ์
์ฑ์ฝ๋ ํ๋ณธ์์ base64 ์ํ๋ฒณ์ strings ๋ก ์ฐพ๋ค ๋ชป ์ฐพ๊ณ "์ธ์ฝ๋๊ฐ ์๋ ๋ณด๋ค" ํ๊ณ ๋์ด๊ฐ๋ฉด ๋ฑ ์ด ๊ฒฝ์ฐ๋ค. ์ฆ์น๊ฐ 8๊ฐ๋ฅผ ๋ฆฌํ์๋์ธ์ผ๋ก ๋๋๋ฆฌ๋ฉด 64์๊ฐ ๊ทธ๋๋ก ๋์จ๋ค.
๐ ๋ฐํ์ ๊ฒ์ฆ โ 6๋นํธ 4์กฐ๊ฐ์ ๋์ผ๋ก ๋ณธ๋ค
์ ์ ์ผ๋ก ์ง์ ๊ฒ ์คํ ์ค์๋ ๋ง๋์ง ํ์ธํ๋ค. ์ธํฐ๋ํฐ๋ธ ์ธ์
์์ด -batch ๋ก ๋๋ฆฐ๋ค.
# cmds.gdb โ ๋ฐฐํฌ๋ณธ for ๋ฃจํ๋ฅผ ํ ๋ฐํด์ฉ ๋ฉ์ถฐ 6๋นํธ ๊ทธ๋ฃน -> Table ์์ธ์ ์ค์ธกํ๋ค.
# ์คํ: gdb -q -batch -x cmds.gdb --args ./l05
# ์
๋ ฅ "Man"(0x4D 0x61 0x6E) ์ run ์ ๋ฆฌ๋ค์ด๋ ์
์ผ๋ก ์ค๋ค.
set pagination off
set confirm off
break snippet.c:32
commands
silent
printf "[์ ์ฌ] StartOfData 3๋ฐ์ดํธ = %02x %02x %02x buffer = 0x%06lx\n", \
(unsigned char)StartOfData[0], (unsigned char)StartOfData[1], \
(unsigned char)StartOfData[2], buffer
continue
end
break snippet.c:37
commands
silent
printf " i=%d buffer=0x%06lx buffer2(=buffer&0x3f)=%2ld -> Table[%2ld]='%c' Output[%d]\n", \
i, buffer, buffer2, buffer2, Table[buffer2], i
continue
end
break snippet.c:55
commands
silent
printf "[๋ฐํ] encoded=%d Output ์ 4๋ฐ์ดํธ = \"%c%c%c%c\"\n", \
encoded, Output[-4], Output[-3], Output[-2], Output[-1]
continue
end
run < t3.bin > /dev/nullgdb -q -batch -x cmds.gdb --args ./l05
buffer ๊ฐ 0x4d616e ์ผ๋ก ์กํ๊ณ , 6๋นํธ์ฉ 46 โ 5 โ 22 โ 19 ์์ผ๋ก ๋น ์ง๋ฉด์ Output[3] ๋ถํฐ ๊ฑฐ๊พธ๋ก ์ฑ์์ง๋ค. ๊ฒฐ๊ณผ๊ฐ TWFu. ์์ ๋์๊ณผ ์ ํํ ๊ฐ์ ๊ทธ๋ฆผ์ด๋ค.
๐ฃ 76์ด ์ ๊ธฐ โ ์ฌ๊ธฐ๊ฐ ์ ์ฒด๋ฅผ ๋ชป๋ฐ๋ ๋ถ๋ถ
์ํ๋ฒณ๊ณผ 6๋นํธ๋ง ๋ณด๋ฉด "base64 ๊ณ์ด"๊น์ง๋ฐ์ ๋ชป ๊ฐ๋ค. if(l==76 && SizeOfData>3) ์ด ๋ถ๋ ์๊ฐ ์๊ธฐ๊ฐ ๋ฌ๋ผ์ง๋ค. 76์ด๋ผ๋ ์ซ์๋ RFC 2045 ๋ง๊ณ ๋์ฌ ๋ฐ๊ฐ ์๋ค.
sh disasm.sh 67 86
cmp DWORD PTR [rbp-0x64],0x4c ๊ฐ 76์ด๊ณ , ๊ทธ ๋ค์ mov BYTE PTR [rax],0xd / 0xa ๊ฐ CR LF ๋ค. 76์๋ง๋ค CRLF ๋ฅผ ๋ผ์ฐ๋ ๊ฑด MIME ๋ณธ๋ฌธ ์ ๊ธฐ ๊ทธ ์์ฒด๋ค.
๊ฐ์ ํ๋ฉด์ ์ด ๊ตฌํ์ ๋ฌธ์ ๋ ๊ฐ๊ฐ ๊ฐ์ด ์ฐํ ์๋ค. cmp ...,0x3 + jle ๋ "๋ง์ง๋ง ๊ทธ๋ฃน๋ง ๋จ์์ผ๋ฉด ์ ์ง ์๋๋ค"๋ ๋ป์ด๊ณ , cmp ...,0x0 + jne ๋ ๋ฃจํ ์ข
๋ฃ ์กฐ๊ฑด์ด >0 ์ด ์๋๋ผ !=0 ์ด๋ผ๋ ๋ป์ด๋ค. ๋ ๋ค ๋ค์์ ์ค์ธกํ๋ค.
๐ ์ฝ์ง
โถ๐ ์ฝ์ง 1 โ ๋ฐ์ดํธ ์์๋ฅผ ๋ฐ๋๋ก ์ฑ์๋ ๊ทธ๋ด๋ฏํ ์ถ๋ ฅ์ด ๋์จ๋ค
๊ฐ๋ ค์ง ์๋ฆฌ๋ฅผ ์ฑ์ธ ๋ ์ฒ์์ ๋ณ์๊ฐ ์์ด StartOfData ๋ฅผ long ์ผ๋ก ์บ์คํ
ํด ์ฝ๋ ์ฝ๋๋ฅผ ๋ฃ์๋ค. x86 ์ ๋ฆฌํ์๋์ธ์ด๋ผ ๊ทธ๋ฌ๋ฉด byte2<<16 | byte1<<8 | byte0 ์ด ๋๋ค.
๋ฌธ์ ๋ ๊ทธ๋ ๊ฒ ํด๋ ์ถ๋ ฅ์ด ๋ฉ์ฉกํ base64 ๋ฌธ์์ด์ฒ๋ผ ์๊ฒผ๋ค๋ ๊ฒ์ด๋ค. ์ํ๋ฒณ์ด ๊ฐ์ผ๋ ๋น์ฐํ๋ค. ๊ธธ์ด๋ ์ ํํ 4/3 ๋ฐฐ๊ณ 76์ด ์ ๊ธฐ๋ ๊ทธ๋๋ก ๋๋ค. ๋์ผ๋ก๋ ๊ตฌ๋ถ์ด ์ ๋๋ค.
๋์กฐ๊ตฐ์ ์์ ๋น๋๋ก ๊ฐ๋ผ ๋๊ณ ํ์ค๊ณผ ๋ง์ถฐ ๋ณด๋ ๊ฒ ์ ์ผํ ๋ฐฉ๋ฒ์ด์๋ค.
# le_control.sh
#!/bin/sh
# le_control.sh โ (A) ์๋ฆฌ๋ฅผ ๋ฐ๋ ๋ฐ์ดํธ์์๋ก ์ฑ์ด ๋์กฐ๊ตฐ.
# ๋ถ์ผ์น๊ฐ ๋์ค๋ ๊ฒ ์ ์์ด๋ค. difftest.py ๋ ๋ถ์ผ์น๊ฐ ์์ผ๋ฉด ์ข
๋ฃ์ฝ๋ 1 ๋ก ๋๋๋ฏ๋ก
# ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋๋ก ํด์ํด ์ฃผ๊ณ 0 ์ผ๋ก ๋ง์น๋ค.
gcc -O0 -g -DLOAD_LITTLE_ENDIAN -o l05_le driver.c snippet.c
python3 difftest.py ./l05_le 300 \
|| echo '(๋ถ์ผ์น = ๊ธฐ๋๊ฐ. ๋ฆฌํ์๋์ธ์ผ๋ก ์ ์ฌํ๋ฉด base64 ๊ฐ ์๋๊ฒ ๋๋ค)'sh le_control.sh
104์ข
์ค 102์ข
๋ถ์ผ์น. ๊ทธ๋ฐ๋ฐ 2์ข
์ ํต๊ณผํ๋ค. 0x00 300๊ฐ์ 0xff 300๊ฐ๋ค. ๋ชจ๋ ๋ฐ์ดํธ๊ฐ ๊ฐ์ผ๋ฉด ๋ค์ง์ด๋ ๊ฐ์ ๊ฐ์ด๋ผ ๋น์ฐํ ์ผ์ธ๋ฐ, ๋ง์ฝ ํ
์คํธ ์
๋ ฅ์ ๊ทธ๋ฐ ๋ฐ๋ณต ํจํด์ผ๋ก๋ง ์ก์์ผ๋ฉด ์ค๋
์ ๋ชป ์ก๊ณ ๊ทธ๋๋ก ๋์ด๊ฐ์ ๊ฒ์ด๋ค.
๊ทธ๋์ ๋์กฐ ์
๋ ฅ์ ๋ฌด์์ ๋ฐ์ดํธ์ด์ ๋ฃ๊ณ , ๊ฑฐ๊ธฐ์ ๋ํด bytes(range(256))*3 ์ฒ๋ผ ๋ชจ๋ ๋ฐ์ดํธ ๊ฐ์ด ํ ๋ฒ์ฉ ๋์ค๋ ์ผ์ด์ค๋ฅผ ์์๋ค.
โถ๐ ์ฝ์ง 2 โ MIME ์๋ณต ํ ์คํธ ๊ธธ์ด๋ฅผ ํํ ํจ์ ๊ธธ์ด๋ก ์ก์๋ค
์ต์ข ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฒ์ ์งค ๋, ๋ฉ์ผ ํ์ ์๋ณต ๊ฒ์ฌ์ ํต๊ณผ ์กฐ๊ฑด์ "๋ชจ๋ ์ค์ด 76์ ์ดํ"๊น์ง ๊ฐ์ด ๋ฃ์๋ค. ๊ทธ๋ฆฌ๊ณ ํ ์คํธ ํ์ด๋ก๋ ๊ธธ์ด๊ฐ ์ฐ์ฐํ 288๋ฐ์ดํธ๋ก ์กํ๋ค.
๊ฒฐ๊ณผ๋ ํ์ ์คํจ. ๋ค๋ฅธ ์ธ ํญ๋ชฉ์ ๋ค ํต๊ณผ์ธ๋ฐ ๋ค ๋ฒ์งธ๋ง False ๋ก ๋จ์ด์ก๋ค.
ํ์ฐธ ์ฝ๋๋ฅผ ๋ค์ฌ๋ค๋ณด๋ค๊ฐ 288 = 57ร5 + 3 ์ด๋ผ๋ ๊ฑธ ์์์ฑ๋ค. ๋ค์ ๋์ค๋ ์ค๋ฐ๊ฟ ๊ฒฐํจ์ด ์ ํํ ๊ทธ ๊ธธ์ด์์ ํฐ์ง๋ค. ์ฆ ์คํฌ๋ฆฝํธ๊ฐ ํ๋ฆฐ ๊ฒ ์๋๋ผ ๋ฐฐํฌ๋ณธ์ด ์ค์ ๋ก ๊ท๊ฒฉ์ ์ด๊ธฐ๋ ์ง์ ์ ๋ด๊ฐ ์ฐ์ฐํ ๋ฐ์ ๊ฒ์ด์๋ค.
ํ์ ๊ธฐ์ค์ ๋๋ก ์ชผ๊ฐ์ ์ ๋ฆฌํ๋ค. ๋ฉ์ผ ํ์๊ฐ ์ฒจ๋ถ๋ฅผ ๋ณต์ํ๋๊ฐ(์ด๊ฑด ํต๊ณผํด์ผ ํ๋ค)์ 76์ด ์ํ์ ์งํค๋๊ฐ(์ด๊ฑด 57k+3 ์์ ๊นจ์ง๋ ๊ฒ ๋ง๋ค)๋ฅผ ๋ฐ๋ก ์ฐ๊ฒ ํ๋ค.
๐ฏ ํ์ โ ํ์ค๊ณผ ์ ์ ๋์กฐ
์ฌ๊ธฐ๊น์ง๋ ์ ํฉ์ด๋ค. "์ด ํจ์์ ์ถ๋ ฅ์ด ๊ณง base64" ๋ฅผ ๋งํ๋ ค๋ฉด ํ์ค ๊ตฌํ๊ณผ ๋ฐ์ดํธ ๋จ์๋ก ๋ง์์ผ ํ๋ค.
์ ๋ต์ง๋ ๋ ๋ฒ๋ก ๋๋ด๋ค. ์ค๋ฐ๊ฟ ์๋ ์์ RFC 4648 base64 ์, 76์ด CRLF ๋ก ์ ์ RFC 2045 MIME.
#!/usr/bin/env python3
"""reference.py โ ๋ฐฐํฌ๋ณธ์ ๋์กฐํ '์ ๋ต์ง' ๋ ๋ฒ.
b64_raw(data) : RFC 4648 ์์ base64 (์ค๋ฐ๊ฟ ์์)
b64_mime(data) : RFC 2045 MIME โ 76์ด๋ง๋ค CRLF, ๋ง์ง๋ง ์ค ๋ค์๋ CRLF ์์
๋ฐฐํฌ๋ณธ 05.txt ๋ Table ์ '=' ๊ฐ ์๊ณ SizeOfData ๋ฅผ 3์ฉ๋ง ๊น์ผ๋ฏ๋ก
๊ธธ์ด๊ฐ 3์ ๋ฐฐ์์ธ ์
๋ ฅ๋ง ๋ค๋ฃฐ ์ ์๋ค. ์ ๋ต์ง๋ ๊ฐ์ ์กฐ๊ฑด์์๋ง ์ด๋ค.
"""
import base64
import sys
def b64_raw(data: bytes) -> bytes:
assert len(data) % 3 == 0, "๋ฐฐํฌ๋ณธ์ 3์ ๋ฐฐ์ ๊ธธ์ด๋ง ์ฒ๋ฆฌํ๋ค"
return base64.b64encode(data)
def b64_mime(data: bytes, width: int = 76) -> bytes:
s = b64_raw(data)
lines = [s[i:i + width] for i in range(0, len(s), width)]
return b"\r\n".join(lines)
if __name__ == "__main__":
raw = sys.stdin.buffer.read()
mode = sys.argv[1] if len(sys.argv) > 1 else "mime"
sys.stdout.buffer.write(b64_mime(raw) if mode == "mime" else b64_raw(raw))๋์กฐ๋ ๋ ๊ฐ๋๋ก ๋ณธ๋ค. CRLF ๋ฅผ ๊ฑท์ด๋ธ ์ํ๋ฒณ ์คํธ๋ฆผ์ด ํ์ค๊ณผ ๊ฐ์๊ฐ(์ธ์ฝ๋ฉ์ ์ ์ฒด)์, ์ค๋ฐ๊ฟ ์์น๊น์ง MIME ๊ณผ ๊ฐ์๊ฐ(๊ท๊ฒฉ ์ค์ ์ฌ๋ถ).
#!/usr/bin/env python3
"""difftest.py โ ๋ฐฐํฌ๋ณธ ํจ์ vs ํ์ค base64 ์ ์ ๋์กฐ.
ํ์ ๋ ๊ฐ๋๋ก ๋๋ ๋ณธ๋ค.
(1) CRLF ๋ฅผ ๊ฑท์ด๋ธ '์ํ๋ฒณ ์คํธ๋ฆผ' ์ด RFC 4648 base64 ์ ๊ฐ์๊ฐ โ ์ธ์ฝ๋ฉ ์ ์ฒด
(2) CRLF ์์น๊น์ง ํฌํจํด RFC 2045 MIME ๊ณผ ๊ฐ์๊ฐ โ ์ค๋ฐ๊ฟ ๊ท๊ฒฉ ์ค์
"""
import random
import subprocess
import sys
from reference import b64_mime, b64_raw
BIN = sys.argv[1] if len(sys.argv) > 1 else "./l05"
MAXLEN = int(sys.argv[2]) if len(sys.argv) > 2 else 900
def run(data: bytes) -> bytes:
return subprocess.run([BIN], input=data, capture_output=True).stdout
def main() -> int:
random.seed(20260819)
cases = []
# ๊ฒฐ์ ์ ํจํด + ๋ฌด์์
for n in range(3, MAXLEN + 1, 3):
cases.append(bytes(random.randrange(256) for _ in range(n)))
cases.append(b"\x00" * 300)
cases.append(b"\xff" * 300)
cases.append(bytes(range(256)) * 3) # 768B, ๋ชจ๋ ๋ฐ์ดํธ๊ฐ
cases.append(b"CodeEngn" * 24) # 192B, ASCII
raw_bad, mime_bad = [], []
for data in cases:
got = run(data)
if got.replace(b"\r\n", b"") != b64_raw(data):
raw_bad.append(len(data))
if got != b64_mime(data):
mime_bad.append(len(data))
print(f"์
๋ ฅ {len(cases)}์ข
(์ต๋ {max(len(c) for c in cases)}B)")
print(f"(1) ์ํ๋ฒณ ์คํธ๋ฆผ == RFC4648 base64 : ๋ถ์ผ์น {len(raw_bad)}๊ฑด")
print(f"(2) ์ค๋ฐ๊ฟ๊น์ง == RFC2045 MIME : ๋ถ์ผ์น {len(mime_bad)}๊ฑด")
if mime_bad:
print(" ๋ถ์ผ์น ๊ธธ์ด:", mime_bad[:12], "..." if len(mime_bad) > 12 else "")
print(" ์ ๋ถ 57k+3 ์ธ๊ฐ:", all((n - 3) % 57 == 0 for n in mime_bad))
return 0 if not raw_bad else 1
if __name__ == "__main__":
raise SystemExit(main())python3 difftest.py ./l05 900
์ํ๋ฒณ ์คํธ๋ฆผ ๋ถ์ผ์น 0๊ฑด. ๋ฌด์์ ๋ฐ์ดํธ์ด 300์ข
์ ์ ๋ฐ์ดํธ ๊ฐ ์ผ์ด์ค, ASCII, ์ ๋ถ 0x00, ์ ๋ถ 0xff ๊น์ง ๋ฃ์ด๋ ํ์ค๊ณผ ํ ๋ฐ์ดํธ๋ ์ ๋ค๋ฅด๋ค.
์ค๋ฐ๊ฟ๊น์ง ๋ณด๋ฉด 15๊ฑด์ด ์ด๊ธ๋๋๋ฐ ๊ทธ ๊ธธ์ด๊ฐ ์ ๋ถ 57k+3 ์ด๋ค. ์ธ์ฝ๋ฉ ์์ฒด๊ฐ ๋ค๋ฅธ ๊ฒ ์๋๋ผ ์ ๊ธฐ ์กฐ๊ฑด ํ๋๊ฐ ์ด๊ธ๋ ๊ฒ์ด๋ค.
์ฌ๊ธฐ์ ์ฐ๋ฆฌ ์ ๋ต์ง๊ฐ ์๋๋ผ ์ 3์ ๋๊ตฌ๊ฐ ์ด ์ถ๋ ฅ์ ๋๋๋ฆฌ๋์ง๋ ๋ณธ๋ค. ๋ด๊ฐ ์ง ์ฝ๋๋ผ๋ฆฌ ๋ง์ถฐ ๋ณด๋ ๊ฑด ๊ฒฐ๊ตญ ๊ฐ์ ๊ฐ์ ์์ ์๋ ๊ฒ์ด๋ผ์๋ค.
# roundtrip.sh
#!/bin/sh
# roundtrip.sh โ ์ 3์ ๋๊ตฌ๊ฐ ๋ฐฐํฌ๋ณธ ์ถ๋ ฅ์ ๋๋๋ฆฌ๋๊ฐ (900B ๋ฌด์์)
head -c 900 /dev/urandom > rt900.bin
echo "์
๋ ฅ rt900.bin = $(stat -c%s rt900.bin) B"
./l05 < rt900.bin > rt900.b64
echo "๋ฐฐํฌ๋ณธ ์ถ๋ ฅ rt900.b64 = $(stat -c%s rt900.b64) B (์ค $(grep -c '' rt900.b64)๊ฐ)"
base64 -d < rt900.b64 > rt900.out
cmp rt900.bin rt900.out && echo 'coreutils base64 -d : ์๋ณธ๊ณผ ์์ ์ผ์น'
tr -d '\r\n' < rt900.b64 | openssl base64 -d -A > rt900.ssl
cmp rt900.bin rt900.ssl && echo 'openssl base64 -d : ์๋ณธ๊ณผ ์์ ์ผ์น'sh roundtrip.sh
base64 -d ๋ openssl base64 -d ๋ ์๋ณธ์ ๊ทธ๋๋ก ๋ณต์ํ๋ค. ๋จ์ด ๋ง๋ ๋์ฝ๋๊ฐ ์ธ์ ํ๋ฉด ๊ทธ๊ฒ base64๋ค.
๋ง์ง๋ง์ผ๋ก ์ฉ๋๊น์ง ํ์ธํ๋ค. 76์ด CRLF ๊ฐ MIME ์ด๋ผ๋ฉด, ์ด ์ถ๋ ฅ์ ๊ทธ๋๋ก ๋ฉ์ผ ๋ณธ๋ฌธ์ ๋ถ์์ ๋ ํ์ค ๋ฉ์ผ ํ์๊ฐ ์ฒจ๋ถํ์ผ๋ก ๋ฏ์ด๋ด์ผ ํ๋ค.
#!/usr/bin/env python3
"""mime_demo.py โ ๋ฐฐํฌ๋ณธ ์ถ๋ ฅ์ ์ง์ง ๋ฉ์ผ ํ์์ ๋จน์ฌ ๋ณธ๋ค.
76์ด CRLF ์ ๊ธฐ๋ RFC 2045(MIME) ๊ท๊ฒฉ์ด๋ค. ์ด ํจ์๊ฐ ์ ๋ฉ์ผ ์ฒจ๋ถ ์ธ์ฝ๋์ธ์ง
๋ง๋ก ์ฃผ์ฅํ์ง ๋ง๊ณ , ํ์ด์ฌ ํ์ค email ํ์๊ฐ ๊ทธ๋๋ก ์ฒจ๋ถํ์ผ๋ก ๋ฏ์ด๋ด๋์ง ๋ณธ๋ค.
1) ์ฒจ๋ถํ ํ์ด๋ก๋๋ฅผ ./l05 ๋ก ์ธ์ฝ๋ฉ (๋ฐฐํฌ๋ณธ ํจ์ ๊ทธ๋๋ก)
2) ๊ทธ ๊ฒฐ๊ณผ๋ฅผ Content-Transfer-Encoding: base64 ๋ณธ๋ฌธ์ผ๋ก ๋ถ์ฌ ๋ฉ์ผ์ ์กฐ๋ฆฝ
3) email.message_from_bytes ๋ก ๋ค์ ํ์ฑ -> get_payload(decode=True)
4) ์๋ณธ ๋ฐ์ดํธ์ ์์ ์ผ์นํ๋์ง ๋น๊ต
"""
import email
import email.policy
import subprocess
import sys
# ์ค์ ์
์ฑ์ฝ๋๋ฅผ ๋ฐฐํฌํ์ง ์๊ธฐ ์ํ ๋๋ฏธ PE ์คํ
(MZ ํค๋ + DOS stub ๋ฌธ๊ตฌ)
PAYLOAD = (b"MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xff\xff\x00\x00"
b"This program cannot be run in DOS mode.\r\n"
b"[DUMMY PE STUB - not a real sample] ") * 3
PAYLOAD = PAYLOAD[:len(PAYLOAD) // 3 * 3] # ๋ฐฐํฌ๋ณธ์ 3์ ๋ฐฐ์๋ง ์ฒ๋ฆฌํ๋ค
body = subprocess.run(["./l05"], input=PAYLOAD, capture_output=True).stdout
msg = (b"From: <postmaster@example.invalid>\r\n"
b"To: <victim@example.invalid>\r\n"
b"Subject: Delivery notification\r\n"
b"MIME-Version: 1.0\r\n"
b"Content-Type: application/octet-stream; name=\"price.exe\"\r\n"
b"Content-Transfer-Encoding: base64\r\n"
b"Content-Disposition: attachment; filename=\"price.exe\"\r\n"
b"\r\n") + body + b"\r\n"
open("worm_mail.eml", "wb").write(msg)
parsed = email.message_from_bytes(msg, policy=email.policy.default)
back = parsed.get_payload(decode=True)
print(f"ํ์ด๋ก๋ ์๋ณธ : {len(PAYLOAD)} B ์ 2๋ฐ์ดํธ = {PAYLOAD[:2]!r}")
print(f"./l05 ์ธ์ฝ๋ฉ ๊ฒฐ๊ณผ : {len(body)} B")
print(f"๋ณธ๋ฌธ ์ค ๊ธธ์ด : {[len(x) for x in body.split(b'CRLF'.replace(b'CRLF', b'\r\n'))]}")
print(f"CTE ํค๋ : {parsed['Content-Transfer-Encoding']}")
print(f"์ฒจ๋ถ ํ์ผ๋ช
: {parsed.get_filename()}")
print(f"ํ์๊ฐ ๋ณต์ํ ๋ฐ์ดํธ : {len(back)} B ์ 2๋ฐ์ดํธ = {back[:2]!r}")
print(f"์๋ณธ๊ณผ ์์ ์ผ์น : {back == PAYLOAD}")
sys.exit(0 if back == PAYLOAD else 1)python3 mime_demo.py && echo "--- worm_mail.eml ์ 12์ค ---" && head -12 worm_mail.eml
Content-Transfer-Encoding: base64 ๋ง ๋ถ์๋๋ฐ ํ์ด์ฌ email ๋ชจ๋์ด price.exe ์ฒจ๋ถ๋ก ์ธ์ํ๊ณ 279๋ฐ์ดํธ๋ฅผ ๊ทธ๋๋ก ๋๋๋ ธ๋ค. ๋ณธ๋ฌธ ์ฒซ ์ค TVqQAAMAAAAEAAAA... ๋ MZ\x90\x00 ๋ก ์์ํ๋ PE ํค๋์ base64 ํํ๋ค. ๋ฉ์ผ ๊ฒ์ดํธ์จ์ด์์ ์ด ๋ฌธ์์ด์ ๋ณด๋ฉด ์คํํ์ผ ์ฒจ๋ถ๋ผ๋ ๋ป์ด๋ค.
์ ๋ต์ base64.
๐งจ ์ด ๊ตฌํ์ด ๊ท๊ฒฉ์ ์ด๊ธฐ๋ ๊ณณ ๋ ๊ตฐ๋ฐ
๋ฌธ์ ์ ๋ต๊ณผ๋ ๋ณ๊ฐ๋ก, ๋ฐ์ท๋ณธ์ ์ค์ ๋ก ๋๋ ค ๋ณด๋ฉด ๊ฒฐํจ์ด ๋ ๊ฐ ๋์จ๋ค. ์ ์ฑ์ฝ๋ ์์ค๋ผ๋ ๋งฅ๋ฝ์์ ํฅ๋ฏธ๋ก์ด ๋ถ๋ถ์ด๋ค.
์ฒซ์งธ, 3์ ๋ฐฐ์๊ฐ ์๋ ์ ๋ ฅ์์ ํจ์๊ฐ ๋๋์ง ์๋๋ค.
SizeOfData-=3 ๋ฅผ ํ๊ณ while(SizeOfData!=0) ๋ก ๊ฒ์ฌํ๋ค. ๋จ์ ํฌ๊ธฐ๊ฐ 2์๋ค๋ฉด -1, -4, -7 ๋ก ๊ณ์ ๋ด๋ ค๊ฐ๋ฉด์ ์์ํ 0์ ๋ชป ๋ง๋๋ค. ๊ทธ ๋์ ์ถ๋ ฅ ํฌ์ธํฐ๋ ๊ณ์ ์ ์งํ๋ฏ๋ก ๋ฒํผ ๋ฐ์ ๋ฎ์ด ์ด๋ค.
# hangtest.sh
#!/bin/sh
# hangtest.sh โ while(SizeOfData!=0) ๊ฐ 3์ ๋ฐฐ์ ์๋ ๊ธธ์ด์์ ๋ฉ์ถ๋๊ฐ
for n in 2 3 4 5 6; do
head -c $n /dev/zero > hang_$n.bin
timeout 3 ./l05 < hang_$n.bin > /dev/null 2>&1
rc=$?
case $rc in
0) msg='์ ์ ์ข
๋ฃ' ;;
124) msg='3์ด ํ์์์ โ ๋ฃจํ๊ฐ ์ ๋๋๋ค' ;;
139) msg='SIGSEGV โ ๋ฒํผ ๋ฐ์ผ๋ก ๊ณ์ ์ด๋ค' ;;
*) msg="์ข
๋ฃ์ฝ๋ $rc" ;;
esac
echo "์
๋ ฅ ${n}B (3์ ๋ฐฐ์: $([ $((n%3)) -eq 0 ] && echo yes || echo no)) -> rc=$rc $msg"
donesh hangtest.sh
2ยท4ยท5๋ฐ์ดํธ๋ ์ ๋ถ 139(SIGSEGV), 3ยท6๋ฐ์ดํธ๋ง ์ ์ ์ข
๋ฃ๋ค. Table ์ = ๊ฐ ์์๋ ๊ฒ ์ฐ์ฐ์ด ์๋์๋ ์
์ด๋ค. ์ด ํจ์๋ ์ ์ด์ ํจ๋ฉ์ ๋ผ ์ ์๊ณ , ํธ์ถ๋ถ๊ฐ 3์ ๋ฐฐ์ ๊ธธ์ด๋ฅผ ๋ณด์ฅํด ์ค๋ค๋ ์ ์ ์์ ์ ์๋ค.
๋์งธ, 76์ด ์ํ์ ์ด๊ธฐ๋ ๊ธธ์ด๊ฐ ์๋ค.
์ ๊ธฐ ์กฐ๊ฑด์ด l==76 && SizeOfData>3 ์ด๋ค. 76์๋ฅผ ์ฑ์ด ์์ ์ ๋จ์ ์
๋ ฅ์ด ์ ํํ 3๋ฐ์ดํธ๋ฉด(=๋ง์ง๋ง ํ ๋ฌถ์) ์ค๋ฐ๊ฟ์ ๊ฑด๋๋ด๋ค. ๊ทธ๋ฌ๋ฉด ๊ทธ ์ค์ 80์๊ฐ ๋๋ค.
#!/usr/bin/env python3
"""linebreak_trap.py โ 76์ด ์ ๊ธฐ ์กฐ๊ฑด์ `&& SizeOfData>3` ์ด ๋ง๋๋ ๊ท๊ฒฉ ์๋ฐ.
RFC 2045 ยง6.8: "The encoded output stream must be represented in lines of no more
than 76 characters each." ๋ฐฐํฌ๋ณธ์ ๋ง์ง๋ง ๊ทธ๋ฃน ํ๋๋ง ๋จ์ ๊ฒฝ๊ณ์์ ์ค๋ฐ๊ฟ์
๊ฑด๋๋ฐ๋ฏ๋ก, ์
๋ ฅ ๊ธธ์ด๊ฐ 57k+3 ์ผ ๋ 80์์ง๋ฆฌ ์ค์ด ๋์จ๋ค.
"""
import subprocess
from reference import b64_mime
CRLF = b"\r\n"
for n in (57, 60, 63, 114, 117):
data = bytes((i * 37 + 11) & 0xFF for i in range(n))
got = subprocess.run(["./l05"], input=data, capture_output=True).stdout
exp = b64_mime(data)
gl = [len(x) for x in got.split(CRLF)]
el = [len(x) for x in exp.split(CRLF)]
verdict = "์ผ์น" if got == exp else f"๋ถ์ผ์น (>76 ์ธ ์ค {sum(1 for x in gl if x > 76)}๊ฐ)"
print(f"์
๋ ฅ {n:4d}B | ๋ฐฐํฌ๋ณธ ์ค๊ธธ์ด {str(gl):16s} | ํ์ค MIME {str(el):16s} | {verdict}")python3 linebreak_trap.py
60๋ฐ์ดํธ ์
๋ ฅ์์ ํ์ค์ 76 + 4 ์ธ๋ฐ ๋ฐฐํฌ๋ณธ์ 80 ํ ์ค์ด๋ค. ์์ ์ ์ ๋์กฐ์์ ๋์จ 15๊ฑด์ด ์ ๋ถ ์ด ๊ฒฝ์ฐ์๋ค.
์ค๋ฌด์ ์ผ๋ก๋ ๋๋ถ๋ถ์ ๋ฉ์ผ ํ์๊ฐ ๊ด๋ํด์ ๊ทธ๋ฅ ์ฝํ๋ค. ๊ทธ๋์ ์กฐ์ฉํ ๋์ด๊ฐ๊ณ , ๋์ ์ด๋ฐ ๋ฏธ๋ฌํ ์ด๊ธ๋จ์ด ๋๊ตฌ ๊ฐ ์ง๋ฌธ์ผ๋ก ๋จ๋๋ค. ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด ๊ฒ ์๋๋ผ ์ง์ ์ง ์ธ์ฝ๋๋ผ๋ ์ ํธ๋ค.
๐ ์ต์ข ํ์ ์คํฌ๋ฆฝํธ
์ง๊ธ๊น์ง์ ๊ทผ๊ฑฐ ๋ค ๊ฐ์ง๋ฅผ ํ ๋ฒ์ ๋๋ ค ๋ต์ ๋ฑ๊ฒ ์ ๋ฆฌํ๋ค.
#!/usr/bin/env python3
"""solve.py โ DreamHack #372 [CodeEngn] Malware L05 ์ต์ข
ํ์ .
๋ฌธ์ : "๋ค์์ ์
์ฑ์ฝ๋ ์์ค์ ์ผ๋ถ๋ถ์ด๋ค. ๋ฌด์์ ํ๋ ํจ์์ธ๊ฐ"
๋ฐฐํฌ๋ณธ 05.txt ๋ ํจ์ ๋ณธ๋ฌธ ๋ ๊ณณ์ด "..." ๋ก ๊ฐ๋ ค์ง 31์ค์ง๋ฆฌ ๋ฐ์ท๋ณธ์ด๋ค.
๋ชจ์๋ง ๋ณด๊ณ ์ฐ์ง ์๋๋ค. ๊ฐ๋ ค์ง ๊ณณ์ ์ฑ์ด ์ฌ๊ตฌ์ฑ๋ณธ(snippet.c)์ ์ปดํ์ผํด
๋ค ๊ฐ์ง๋ฅผ ์ค์ธกํ๊ณ , ๋ท์ด ๋ค ํต๊ณผํ ๋๋ง ๋ต์ ์ถ๋ ฅํ๋ค.
1) Table[] ์ด RFC 4648 ํ์ค ์ํ๋ฒณ๊ณผ ์ธ๋ฑ์ค๋ณ๋ก ์์ ์ผ์นํ๋๊ฐ
2) ์ถ๋ ฅ์ ์ํ๋ฒณ ์คํธ๋ฆผ์ด ํ์ค base64 ์ ๋ฐ์ดํธ ๋จ์๋ก ๊ฐ์๊ฐ (์ ์ ์ค์)
3) ์ 3์ ๋๊ตฌ(coreutils base64 -d / openssl)๊ฐ ๊ทธ ์ถ๋ ฅ์ ๋๋๋ฆฌ๋๊ฐ
4) 76์ด CRLF ์ ๊ธฐ๊ฐ RFC 2045 MIME ์ด์ด์, ์ง์ง ๋ฉ์ผ ํ์๊ฐ ์ฒจ๋ถ๋ก ๋ฏ๋๊ฐ
์ ์ : `gcc -O0 -o l05 driver.c snippet.c` ๋ก l05 ๊ฐ ๋น๋๋ผ ์์ด์ผ ํ๋ค.
"""
import random
import re
import string
import subprocess
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
BIN = HERE / "l05"
def run(data: bytes) -> bytes:
return subprocess.run([str(BIN)], input=data, capture_output=True).stdout
def b64_raw(data: bytes) -> bytes:
import base64
return base64.b64encode(data)
def b64_mime(data: bytes) -> bytes:
s = b64_raw(data)
return b"\r\n".join(s[i:i + 76] for i in range(0, len(s), 76))
def check1_table() -> bool:
src = (HERE / "extracted" / "05.txt").read_bytes().decode("ascii")
table = re.search(r'char\s+Table\[\]\s*=\s*"([^"]*)"', src).group(1)
rfc = string.ascii_uppercase + string.ascii_lowercase + string.digits + "+/"
ok = table == rfc and len(table) == 64 and "=" not in table
print(f"[1] Table[] == RFC4648 Table 1 : {ok} (64์, ํจ๋ฉ '=' ์์)")
return ok
def check2_sweep() -> bool:
random.seed(20260819)
cases = [bytes(random.randrange(256) for _ in range(n)) for n in range(3, 901, 3)]
cases += [b"\x00" * 300, b"\xff" * 300, bytes(range(256)) * 3, b"CodeEngn" * 24]
bad = [len(d) for d in cases if run(d).replace(b"\r\n", b"") != b64_raw(d)]
print(f"[2] ์ํ๋ฒณ ์คํธ๋ฆผ == base64 (์
๋ ฅ {len(cases)}์ข
) : ๋ถ์ผ์น {len(bad)}๊ฑด")
return not bad
def check3_thirdparty() -> bool:
data = bytes((i * 131 + 7) & 0xFF for i in range(900))
enc = run(data)
core = subprocess.run(["base64", "-d"], input=enc, capture_output=True).stdout
flat = enc.replace(b"\r\n", b"")
ssl = subprocess.run(["openssl", "base64", "-d", "-A"],
input=flat, capture_output=True).stdout
ok = core == data and ssl == data
print(f"[3] coreutils base64 -d / openssl ์๋ณต : {ok} (900B)")
return ok
def check4_mime() -> bool:
"""๋ฉ์ผ ํ์๊ฐ ์ฒจ๋ถ๋ก ๋ฏ์ด๋ด๋์ง๊ฐ ํ์ ๋์์ด๋ค.
76์ด ์ํ ์ค์ ์ฌ๋ถ๋ ๋ณ๋๋ก ์ฐ๊ธฐ๋ง ํ๋ค โ 57k+3 ๊ธธ์ด์์๋ ์ผ๋ถ๋ฌ ๊นจ์ง๋ค."""
import email
import email.policy
def roundtrip(payload: bytes):
body = run(payload)
msg = (b"MIME-Version: 1.0\r\n"
b"Content-Type: application/octet-stream\r\n"
b"Content-Transfer-Encoding: base64\r\n\r\n") + body + b"\r\n"
parsed = email.message_from_bytes(msg, policy=email.policy.default)
return body, parsed.get_payload(decode=True)
ok = True
for n in (279, 288): # 288 = 57*5+3 (์ ๊ธฐ ๊ฑด๋๋ฐ๋ ๊ธธ์ด)
payload = bytes((i * 17 + 3) & 0xFF for i in range(n))
body, back = roundtrip(payload)
lines = [len(x) for x in body.split(b"\r\n")]
rfc = all(x <= 76 for x in lines)
ok &= back == payload
print(f"[4] MIME ์ฒจ๋ถ ์๋ณต {n:3d}B : {back == payload}"
f" | ์ค ๊ธธ์ด {lines} -> RFC2045 76์ด ์ค์ {rfc}")
return bool(ok)
def main() -> int:
if not BIN.exists():
print("l05 ๊ฐ ์๋ค. gcc -O0 -o l05 driver.c snippet.c", file=sys.stderr)
return 2
results = [check1_table(), check2_sweep(), check3_thirdparty(), check4_mime()]
print()
if all(results):
print("ํ์ : 3๋ฐ์ดํธ -> 4๋ฌธ์, RFC4648 ์ํ๋ฒณ, RFC2045 76์ด CRLF ์ ๊ธฐ")
print("ANSWER: base64")
return 0
print("ํ์ ๋ณด๋ฅ โ ์ ํญ๋ชฉ ์ค ์คํจ๊ฐ ์๋ค")
return 1
if __name__ == "__main__":
raise SystemExit(main())python3 solve.py
๋ค ํญ๋ชฉ ์ ๋ถ ํต๊ณผ. 288๋ฐ์ดํธ ์ค์์ 76์ด ์ค์ False ๊ฐ ๋จ๋ ๊ฑด ์์์ ๋ณธ ๊ทธ ๊ฒฐํจ์ด๋ค.
์์
ํด๋์๋ ์ ๋จ๊ณ๋ฅผ ์์๋๋ก ๋ค์ ๋๋ reproduce.sh ๋ฅผ ๋๋ค. ๋ง์ง๋ง ์ค์ด PASS base64 ๋ฉด ์ฑ๊ณต์ด๋ค.
# reproduce.sh (๋ฐ์ท)
#!/bin/sh
set -e
cd "$(dirname "$0")"
sh recon.sh # 1. ๋ฐฐํฌ๋ณธ ์ ์ฐฐ
sh firstrun.sh # 2. ์ฌ๊ตฌ์ฑ๋ณธ ๋น๋ + ์ต์ ๊ฒ์ฆ
python3 table_check.py | head -4 # 3. ์ํ๋ฒณ ๋์กฐ
sh disasm.sh 67 86 # 4. ์ ์ ๋ถ์
gdb -q -batch -x cmds.gdb --args ./l05 # 5. ๋ฐํ์ ๊ฒ์ฆ
python3 difftest.py ./l05 900 # 6. ํ์ค๊ณผ ์ ์ ๋์กฐ
sh le_control.sh # 7. ๋ฐ์ดํธ์์ ์ค๋
๋์กฐ๊ตฐ
sh roundtrip.sh # 8. ์ 3์ ๋๊ตฌ ์๋ณต
python3 mime_demo.py # 9. MIME ์ฒจ๋ถ ์๋ณต
sh hangtest.sh && python3 linebreak_trap.py # 10. ๊ตฌํ ๊ฒฐํจ 2์ข
python3 solve.py | tail -3 # 11. ์ต์ข
ํ์
echo 'PASS base64'๋ก์ปฌ ํ๊ฒฝ: Ubuntu 6.17 x86-64 / gcc 15.2.0 / Python 3.13.7 / GNU binutils objdumpยทgdb / uutils coreutils 0.2.2 base64 / OpenSSL 3.5.3.
๐ ๊ฒฐ๋ก
"๋ชจ์์ด base64 ๊ฐ๋ค"์ "base64๋ค" ์ฌ์ด์๋ ์ค์ธก์ด ํ๋ ๋ค์ด๊ฐ๋ค.
์ด ๋ฌธ์ ๋ ์ํ๋ฒณ 64์๋ง ๋ณด๊ณ ๋ ๋ต์ ์ฐ์ ์ ์๋ค. ์ค์ ๋ก ๊ทธ๋ ๊ฒ ์ฐ์ด๋ ๋ง๋๋ค. ๋ค๋ง Malware L03์์ ์ธํฐ๋ท ์ฒดํฌ์ฌ์ crc ๋ก ๋ถ๋ฅผ ๋ปํ๋ ๊ฒฝํ์ด ์์ด์, ์ด๋ฒ์ ๋ฐ์ท๋ณธ์ ์ปดํ์ผํด ํ์ค๊ณผ ๋ง์ถ๋ ์ชฝ์ ํํ๋ค.
๊ทธ ๋์ ์ป์ ๊ฒ๋ ์๋ค. ๊ฐ๋ ค์ง ์๋ฆฌ๋ฅผ ๋ฐ๋ ๋ฐ์ดํธ ์์๋ก ์ฑ์๋ ๊ฒ๋ณด๊ธฐ์ ๋ฉ์ฉกํ base64 ๋ฌธ์์ด์ด ๋์จ๋ค๋ ๊ฒ, ๊ทธ๋ฆฌ๊ณ 0x00 ๋ฐ๋ณต ๊ฐ์ ์
๋ ฅ์ผ๋ก๋ ๊ทธ ์ค๋
์ด ์ ์กํ๋ค๋ ๊ฒ. ๋ฐ์ท๋ณธ ๋ณต์์ ๋๋์ค์ผ๋ก ํ๋ฉด ์ ๋๋ ์ด์ ๊ฐ ์ฌ๊ธฐ ์๋ค.
76์ด๋ผ๋ ์ซ์๊ฐ ์ฌ์ค์ ์ง๋ฌธ์ด๋ค.
6๋นํธ ๋ง์คํฌ์ 64์ ์ํ๋ฒณ์ base64 ๊ณ์ด์ด๋ผ๋ฉด ๋ค ๊ฐ๊ณ ์๋ค. ๋ฐ๋ฉด 76์ด CRLF ์ ๊ธฐ๋ RFC 2045 ๊ฐ ๋ฉ์ผ ๋ณธ๋ฌธ ๋๋ฌธ์ ์ ํ ๊ฐ์ด๋ผ, ๊ทธ ์ซ์๊ฐ ๋ณด์ด๋ฉด ์ด ์ธ์ฝ๋๊ฐ ๋ถ๋ ์๋ฆฌ๊ฐ ๋ฉ์ผ์ด๋ผ๋ ๋ป์ด ๋๋ค. ๊ฐ์ ์๋ฆฌ์ฆ์ ๋ค๋ฅธ ๋ฌธ์ ๋ค์ด SMTP ์์ปค๋ฅผ ๋ค๋ฃจ๋ ๊ฒ๊ณผ ์๋ค๊ฐ ๋ง๋๋ค.
๋ถ์ํ ๋: strings ์ ์ ๋์จ๋ค๊ณ ์ธ์ฝ๋๊ฐ ์๋ ๊ฒ ์๋๋ค.
char Table[] ์ด ์ง์ญ ๋ฐฐ์ด์ด๋ฉด ์ปดํ์ผ๋ฌ๊ฐ movabs ์ฆ์น๊ฐ์ผ๋ก ์คํ์ ๊น์ ๋ฒ๋ฆฐ๋ค. ์ค์ ๋ก ์ด ๋น๋์์ strings ๋งค์น๋ 0๊ฑด์ด์๋ค. ํ๋ณธ์์ base64 ์ํ๋ฒณ์ ๋ฌธ์์ด๋ก ์ฐพ๋ค ๋ชป ์ฐพ์ผ๋ฉด, 8๋ฐ์ดํธ ์ฆ์น๊ฐ ์ฌ๋ ๊ฐ๊ฐ ์ฐ๋ฌ์ ์คํ์ ์ค๋ฆฌ๋ ํจํด์ ์ฐพ๋ ์ชฝ์ด ๋น ๋ฅด๋ค. YARA ๋ฃฐ์ ์ธ ๋๋ ๋ฌธ์์ด๋ณด๋ค ์ด์ชฝ์ด ์ก๊ธฐ ์ฝ๋ค.
๋ฐฉ์ด ์ชฝ์์ ๋ณผ ๊ฒ.
๋ฉ์ผ ๊ฒ์ดํธ์จ์ด๋ ์ฒจ๋ถ ๋ณธ๋ฌธ์ ๋์ฝ๋ํด ์ค์ ๋งค์ง ๋ฐ์ดํธ๋ฅผ ๋ด์ผ ํ๋ค. Content-Type ์ด application/octet-stream ์ด๋ ๋ญ๋ , TVqQAA ๋ก ์์ํ๋ base64 ๋ MZ ํค๋๋ค. ํ์ฅ์์ ์ ์ธ ํ์
๋ง ๋ฏฟ์ผ๋ฉด price.exe ๋ฅผ price.txt ๋ก ๋ฐ๊ฟ ๋จ ๊ฒ๋ ๋ชป ๊ฑธ๋ฌ๋ธ๋ค.
๊ทธ๋ฆฌ๊ณ ์ธ์ฝ๋์ ๋ฏธ์ธํ ๊ท๊ฒฉ ์ด๊ธ๋จ โ ์ฌ๊ธฐ์๋ 57k+3 ๊ธธ์ด์ 80์ ์ค โ ์ ๊ทธ ์์ฒด๊ฐ ํ์ง ์ ํธ๊ฐ ๋๋ค. ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ผ๋ค๋ฉด ๋์ฌ ์ ์๋ ์ถ๋ ฅ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ์ ์ ๋ฉ์ผ๊ณผ ์์ฌ ๋ค์ด์ค๋ ํธ๋ํฝ์์ "์ง์ ์ง ์ธ์ฝ๋"๋ฅผ ๊ตฌ๋ถํ๋ ๋ฐ ์ธ ์ ์๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ