๐Ÿ›๐Ÿ’ฃ Sasser (2004) โ€” ํŒจ์น˜ 17์ผ ๋งŒ์— ํ„ฐ์ง„ LSASS ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ: 60์ดˆ ์ข…๋ฃŒ ์นด์šดํŠธ๋‹ค์šดยท5554 FTP ์ž๊ธฐ๋ณต์ œ, 18์„ธ ์ €์ž๊ฐ€ ๋‚จ๊ธด ๊ตํ›ˆ

2026-10-20 ยท Malware Deep-Dive (Worm ยท LSASS ยท MS04-011 ยท CVE-2003-0533 ยท Buffer Overflow ยท 2004)
๊ธฐ์ˆ  ์ •๋ณด
  • ์•…์„ฑ์ฝ”๋“œ๋ช…: Sasser (W32/Sasser, Net-Worm:W32/Sasser, Worm:Win32/Sasser.A~F) โ€” ์ด๋ฆ„์€ LSASS(Security Authority SubSystem Service)์—์„œ ๋”ฐ์™”๋‹ค
  • ๋“ฑ์žฅ: 2004๋…„ 4์›” 30์ผ ์ตœ์ดˆ ์œ ํฌ(Sasser.A) โ†’ 5์›” ์ดˆ BยทCยทD, ์ €์ž ๊ฒ€๊ฑฐ ์งํ›„ Sasser.E
  • ์ทจ์•ฝ์ : MS04-011 / CVE-2003-0533 โ€” LSASS์˜ AD ๊ด€๋ จ ๋ฏธ๋ฌธ์„œํ™” API(DsRolerUpgradeDownlevelDatabase)๋กœ ์ „๋‹ฌ๋˜๋Š” ๊ธด ๋ฌธ์ž์—ด์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์›๊ฒฉ ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ
  • ํŒจ์น˜์™€์˜ ๊ฐ„๊ฒฉ: ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ๊ฐ€ 2004๋…„ 4์›” 13์ผ MS04-011์„ ๋ฐฐํฌ โ†’ ์›œ ๋“ฑ์žฅ๊นŒ์ง€ 17์ผ. ํŒจ์น˜๋ฅผ ๋ฆฌ๋ฒ„์‹ฑํ•ด ์ต์Šคํ”Œ๋กœ์ž‡์„ ๋งŒ๋“ค์—ˆ๋‹ค๋Š” ๋ถ„์„์ด ์œ ๋ ฅํ•˜๋‹ค
  • ์ „ํŒŒ: ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์—†์Œ. TCP 445(SMB, ์ผ๋ถ€ ๋ถ„์„์€ 139๋„ ์–ธ๊ธ‰) ์Šค์บ” โ†’ ์ต์Šคํ”Œ๋กœ์ž‡ ์„ฑ๊ณต ์‹œ 9996 ํฌํŠธ์— ์›๊ฒฉ ์…ธ โ†’ ๊ฐ์—ผ ํ˜ธ์ŠคํŠธ์˜ 5554 FTP ์„œ๋ฒ„์—์„œ ์ž๊ธฐ ์ž์‹ ์„ ๋‚ด๋ ค๋ฐ›์•„ ์‹คํ–‰
  • ํ”์ : %WINDIR%\avserve.exe(A) / avserve2.exe(B~E), C:\win.logยทwin2.log, HKLM\...\Run ์ž๋™ ์‹คํ–‰ ํ‚ค, ๋ฌด์ž‘์œ„ ftp.exe ํ”„๋กœ์„ธ์Šค, CPU 100%
  • ๋Œ€ํ‘œ ์ฆ์ƒ: LSASS ํฌ๋ž˜์‹œ โ†’ "LSA Shell (Export Version)์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค" โ†’ 60์ดˆ ์‹œ์Šคํ…œ ์ข…๋ฃŒ ์นด์šดํŠธ๋‹ค์šด โ†’ ์žฌ๋ถ€ํŒ… โ†’ ๋‹ค์‹œ ๊ฐ์—ผ๋˜๋Š” ๋ถ€ํŒ… ๋ฃจํ”„
  • ํ”ผํ•ด: ์ „ ์„ธ๊ณ„ 100๋งŒ ๋Œ€ ์ด์ƒ ๊ฐ์—ผ(์ถ”์ •). ๋ธํƒ€ํ•ญ๊ณต ๋Œ€์„œ์–‘ ํšก๋‹จํŽธ ๊ฒฐํ•ญ, AFP ์œ„์„ฑ ํ†ต์‹  ๋‘์ ˆ, ํ•€๋ž€๋“œ If/Sampo 130๊ฐœ ์ง€์  ํ์‡„, ์˜๊ตญ ํ•ด์•ˆ๊ฒฝ๋น„๋Œ€ ์ „์žํ•ด๋„ ์„œ๋น„์Šค ์ค‘๋‹จ, ๋ฃฌ๋“œ ๋Œ€ํ•™๋ณ‘์› X-ray 4๋Œ€ ์ •์ง€
  • ์ €์ž: Sven Jaschan(๋‹น์‹œ 18์„ธ, ๋…์ผ ๋กœํ…๋ถ€๋ฅดํฌ). 2004๋…„ 5์›” 7์ผ ์ฒดํฌ(๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ ํ˜„์ƒ๊ธˆ 25๋งŒ ๋‹ฌ๋Ÿฌ ์ œ๋ณด), 2005๋…„ 7์›” 8์ผ ์ง•์—ญ 1๋…„ 9๊ฐœ์›” ์ง‘ํ–‰์œ ์˜ˆ. Netsky.AC๋„ ๊ทธ์˜ ์ž‘ํ’ˆ์ด์—ˆ๋‹ค
  • ์˜์˜: "ํŒจ์น˜๊ฐ€ ๋‚˜์™”๋‹ค"์™€ "ํŒจ์น˜๊ฐ€ ๊น”๋ ธ๋‹ค" ์‚ฌ์ด์˜ ๊ฐ„๊ฒฉ์ด ๊ณง ๊ณต๊ฒฉ ํ‘œ๋ฉด์ž„์„ ๋ณด์—ฌ์ค€ ์‚ฌ๋ก€. ํŒŒ๊ดดยท์œ ์ถœ ์—†์ด๋„ ๊ฐ€์šฉ์„ฑ๋งŒ์œผ๋กœ ์‚ฌํšŒ ๊ธฐ๋ฐ˜์‹œ์„ค์„ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ์Œ์„ ์ฆ๋ช…ํ–ˆ๋‹ค

1. ๋ฐฐ๊ฒฝ/์—ญ์‚ฌ โ€” 18๋ฒˆ์งธ ์ƒ์ผ๋‚  ํ’€๋ ค๋‚œ ์›œ

2004๋…„ 4์›” 13์ผ, ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ๋Š” ์›”๊ฐ„ ๋ณด์•ˆ ์—…๋ฐ์ดํŠธ์˜ ํ•˜๋‚˜๋กœ MS04-011์„ ๋ฐฐํฌํ–ˆ๋‹ค. ์ด ์ค‘ ํ•˜๋‚˜๊ฐ€ Windows 2000ยทXP์˜ LSASS(Local Security Authority Subsystem Service)์—์„œ ๋ฐœ๊ฒฌ๋œ ์›๊ฒฉ ์ฝ”๋“œ ์‹คํ–‰ ์ทจ์•ฝ์  CVE-2003-0533์ด์—ˆ๋‹ค. LSASS๋Š” ๋กœ๊ทธ์˜จยท์ธ์ฆยท์ •์ฑ… ์ ์šฉ์„ ๋‹ด๋‹นํ•˜๋Š” ๋ณด์•ˆ์˜ ์‹ฌ์žฅ์œผ๋กœ, SYSTEM ๊ถŒํ•œ์œผ๋กœ ๋™์ž‘ํ•˜๊ณ  ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์œผ๋ฉด OS๊ฐ€ ์น˜๋ช…์  ์˜ค๋ฅ˜๋กœ ํŒ๋‹จํ•œ๋‹ค.

17์ผ ๋’ค์ธ 2004๋…„ 4์›” 30์ผ, ์ด ์ทจ์•ฝ์ ์„ ์ž๋™์œผ๋กœ ํ„ฐ๋œจ๋ฆฌ๋Š” ์›œ์ด ๋“ฑ์žฅํ–ˆ๋‹ค. ์ œ์ž‘์ž๋Š” ๋…์ผ ๋‹ˆ๋”์ž‘์„ผ ๋กœํ…๋ถ€๋ฅดํฌ์˜ ๊ธฐ์ˆ ์ „๋ฌธ๋Œ€ ํ•™์ƒ Sven Jaschan(๋‹น์‹œ 18์„ธ). ์›œ์€ ๊ทธ์˜ 18๋ฒˆ์งธ ์ƒ์ผ(4์›” 29์ผ)์— ๋งž์ถฐ ์œ ํฌ๋œ ๊ฒƒ์œผ๋กœ ์•Œ๋ ค์กŒ๋‹ค. ๊ทธ๋Š” ๊ฐ™์€ ์‹œ๊ธฐ Netsky ๋ณ€์ข…(Netsky.AC)๋„ ๋งŒ๋“ค์—ˆ๊ณ , ๋‘ ์•…์„ฑ์ฝ”๋“œ๋Š” ๋‹น์‹œ ์œ ํ–‰ํ•˜๋˜ Bagle ๊ณ„์—ด๊ณผ์˜ '๋ฐ”์ด๋Ÿฌ์Šค ์ „์Ÿ' ๊ตฌ๋„ ์†์—์„œ ์„œ๋กœ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ธฐ๋Šฅ๊นŒ์ง€ ๋„ฃ์œผ๋ฉฐ ์ง„ํ™”ํ–ˆ๋‹ค.

๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ๋Š” 25๋งŒ ๋‹ฌ๋Ÿฌ ํ˜„์ƒ๊ธˆ์„ ๊ฑธ์—ˆ๊ณ , ์ง€์ธ์˜ ์ œ๋ณด๋กœ 5์›” 7์ผ Jaschan์ด ์ฒดํฌ๋๋‹ค. ๋…์ผ ๋ฒ•์›์€ ๊ทธ๊ฐ€ ๋งŒ 18์„ธ ์ด์ „์— ์›œ์„ ์ž‘์„ฑํ–ˆ๋‹ค๊ณ  ๋ณด์•„ ์†Œ๋…„๋ฒ•์œผ๋กœ ์žฌํŒํ–ˆ๊ณ , 2005๋…„ 7์›” 8์ผ ์ปดํ“จํ„ฐ ์‚ฌ๋ณดํƒ€์ฃผยท๋ฐ์ดํ„ฐ ๋ถˆ๋ฒ• ๋ณ€๊ฒฝ ํ˜์˜๋กœ ์ง•์—ญ 1๋…„ 9๊ฐœ์›” ์ง‘ํ–‰์œ ์˜ˆ๋ฅผ ์„ ๊ณ ํ–ˆ๋‹ค. ์ฒดํฌ ์งํ›„์—๋„ Sasser.E๊ฐ€ ์œ ํฌ๋๋Š”๋ฐ, ์ด ๋ณ€์ข…์€ ๋‹ค๋ฅธ ์›œ์„ ์ œ๊ฑฐํ•˜๋Š” โ€˜๋ฐฑ์‹  ํ‰๋‚ดโ€™ ๊ธฐ๋Šฅ์„ ๋„ฃ์€ ์œ ์ผํ•œ ํŒ๋ณธ์ด์—ˆ๋‹ค.

2. ๊ฐ์—ผยท์ „ํŒŒ ๊ฒฝ๋กœ โ€” ๋ฉ”์ผ๋„, ํด๋ฆญ๋„ ํ•„์š” ์—†๋‹ค

Sasser์˜ ๊ฐ€์žฅ ํฐ ํŠน์ง•์€ ์‚ฌ์šฉ์ž ํ–‰์œ„๊ฐ€ ์ „ํ˜€ ๊ฐœ์ž…๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค. ์ฒจ๋ถ€ํŒŒ์ผ์„ ์—ด์ง€๋„, ๋งํฌ๋ฅผ ๋ˆ„๋ฅด์ง€๋„ ์•Š๋Š”๋‹ค. ๋„คํŠธ์›Œํฌ์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ณ  445๋ฒˆ ํฌํŠธ๊ฐ€ ์—ด๋ ค ์žˆ์œผ๋ฉฐ ํŒจ์น˜๊ฐ€ ์•ˆ ๋˜์–ด ์žˆ์œผ๋ฉด, ๊ทธ ์ž์ฒด๋กœ ๊ฐ์—ผ ๋Œ€์ƒ์ด๋‹ค.

  1. IP ์ƒ์„ฑ โ€” ๊ฐ์—ผ ํ˜ธ์ŠคํŠธ๋Š” ์ž๊ธฐ IP๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ฃผ๋ณ€ ์ฃผ์†Œ๋ฅผ ๋Œ€๋Ÿ‰ ์ƒ์„ฑํ•œ๋‹ค. ๊ฐ™์€ ๋Œ€์—ญ์„ ์šฐ์„ ํ•˜๋˜ ๋ฌด์ž‘์œ„์„ฑ์„ ์„ž์–ด, ํ•œ ์„œ๋ธŒ๋„ท์ด ๋ง‰ํžˆ๋ฉด ๋‹ค๋ฅธ ๋Œ€์—ญ์œผ๋กœ ๋ฒˆ์ง€๋Š” ๊ตฌ์กฐ๋‹ค.
  2. 445/TCP ์—ฐ๊ฒฐ โ€” SMB ํ˜‘์ƒ ํฌํŠธ์— ๋™์‹œ ๋‹ค๋ฐœ๋กœ ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•œ๋‹ค. ์‘๋‹ต์ด ์žˆ์œผ๋ฉด ๊ณง๋ฐ”๋กœ ์ต์Šคํ”Œ๋กœ์ž‡ ํŒจํ‚ท์„ ๋ณด๋‚ธ๋‹ค.
  3. LSASS ์˜ค๋ฒ„ํ”Œ๋กœ โ€” ์กฐ์ž‘๋œ DCERPC ์š”์ฒญ์˜ ๊ธด ๋ฌธ์ž์—ด์ด LSASS ๋‚ด๋ถ€ ๋ฒ„ํผ๋ฅผ ๋„˜์น˜๊ฒŒ ํ•ด ์‹คํ–‰ ํ๋ฆ„์„ ๊ฐ€๋กœ์ฑˆ๋‹ค.
  4. 9996 ๋ฆฌ์Šค๋„ˆ โ€” ์…ธ์ฝ”๋“œ๊ฐ€ cmd.exe๋ฅผ 9996๋ฒˆ ํฌํŠธ์— ๋ฌถ์–ด ์›๊ฒฉ ์…ธ์„ ๋งŒ๋“ ๋‹ค. ์›œ์€ ์—ฌ๊ธฐ์— ์ ‘์†ํ•ด ๋ช…๋ น์„ ๋‚ด๋ฆฐ๋‹ค.
  5. 5554 FTP์—์„œ 2๋‹จ๊ณ„ ๋‚ด๋ ค๋ฐ›๊ธฐ โ€” ๊ฐ์—ผ ํ˜ธ์ŠคํŠธ๋Š” ์ž์‹ ์˜ 5554๋ฒˆ ํฌํŠธ์— ์ดˆ๋ฏธ๋‹ˆ FTP ์„œ๋ฒ„๋ฅผ ๋„์šฐ๊ณ , ๋ฌด์ž‘์œ„ 5์ž๋ฆฌ ์ˆซ์ž + _up.exe ์ด๋ฆ„์œผ๋กœ ์ž๊ธฐ ๋ณต์‚ฌ๋ณธ์„ ์ œ๊ณตํ•œ๋‹ค. ์ƒˆ ํ˜ธ์ŠคํŠธ๋Š” ftp.exe๋ฅผ ์ด์šฉํ•ด ์ด ํŒŒ์ผ์„ ๋ฐ›์•„ ์‹คํ–‰ํ•œ๋‹ค.
  6. ์ƒ์ฃผ โ€” %WINDIR%\avserve.exe(๋˜๋Š” avserve2.exe)๋กœ ์ €์žฅ๋˜๊ณ  Run ํ‚ค์— ๋“ฑ๋ก๋ผ ์žฌ๋ถ€ํŒ… ํ›„์—๋„ ์‚ด์•„๋‚œ๋‹ค.

์ฆ‰ Sasser๋Š” ์ต์Šคํ”Œ๋กœ์ž‡(1๋‹จ๊ณ„)๊ณผ ํŒŒ์ผ ์ „๋‹ฌ(2๋‹จ๊ณ„)์„ ๋ถ„๋ฆฌํ–ˆ๋‹ค. ์ต์Šคํ”Œ๋กœ์ž‡ ์ฝ”๋“œ๋Š” ์ž‘๊ฒŒ ์œ ์ง€ํ•˜๊ณ , ์‹ค์ œ ํŽ˜์ด๋กœ๋“œ๋Š” ์ด๋ฏธ ๊ฐ์—ผ๋œ ํ˜ธ์ŠคํŠธ๊ฐ€ FTP๋กœ ๊ฑด๋„ค์ฃผ๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ด ๊ตฌ์กฐ ๋•๋ถ„์— ์›œ ๋ณธ์ฒด๋Š” ์ˆ˜์‹ญ KB ์ˆ˜์ค€์œผ๋กœ ์ž‘์•˜๊ณ , ๋ณ€์ข… ๊ต์ฒด๋„ ์‰ฌ์› ๋‹ค.

3. ๋™์ž‘ ์›๋ฆฌ ์ƒ์„ธ โ€” ์ฝ”๋“œ/๊ตฌ์กฐ ๋ ˆ๋ฒจ

3.1 ์ทจ์•ฝ์ ์˜ ๋ณธ์ฒด: ๊ธธ์ด๋ฅผ ๋ฏฟ๋Š” ํŒŒ์„œ

CVE-2003-0533์˜ ๊ทผ๋ณธ ์›์ธ์€ ๊ณ ์ „์ ์ด๋‹ค. ๋„คํŠธ์›Œํฌ์—์„œ ์˜จ ๊ธธ์ด ๊ฐ’์„ ๊ฒ€์ฆํ•˜์ง€ ์•Š๊ณ  ๊ณ ์ • ํฌ๊ธฐ ๋ฒ„ํผ๋กœ ๋ณต์‚ฌํ•˜๋Š” ์Šคํƒ/ํž™ ์˜ค๋ฒ„ํ”Œ๋กœ๋‹ค. ๊ณต๊ฒฉ์ž๋Š” ํ•„๋“œ ํฌ๊ธฐ(์ˆ˜์‹ญ~์ˆ˜๋ฐฑ ๋ฐ”์ดํŠธ)๋ฅผ ํ›จ์”ฌ ๋„˜๋Š” ๋ฌธ์ž์—ด์„ ๋ณด๋‚ด ์ธ์ ‘ ๋ฉ”๋ชจ๋ฆฌ(ํ•จ์ˆ˜ ํฌ์ธํ„ฐยท๋ฆฌํ„ด ์ฃผ์†Œยท์ธ์ฆ ์ƒํƒœ ํ”Œ๋ž˜๊ทธ)๋ฅผ ๋ฎ์–ด์“ด๋‹ค. LSASS๋Š” SYSTEM ๊ถŒํ•œ์ด๋ฏ€๋กœ, ์‹คํ–‰ ํ๋ฆ„์„ ์žก์œผ๋ฉด ๊ณง๋ฐ”๋กœ ์ตœ๊ณ  ๊ถŒํ•œ์ด๋‹ค.

์ค‘์š”ํ•œ ์ ์€ ์ต์Šคํ”Œ๋กœ์ž‡ ์„ฑ๊ณต์ด ๊ณง ์•ˆ์ •์  ๋™์ž‘์„ ์˜๋ฏธํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์›œ์˜ ์…ธ์ฝ”๋“œ๋Š” ๋งค์šฐ ๊ฑฐ์น ๊ฒŒ ์ž‘์„ฑ๋ผ, ์ต์Šคํ”Œ๋กœ์ž‡์ด ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ํž™ ์ƒํƒœ๊ฐ€ ์กฐ๊ธˆ๋งŒ ๋‹ฌ๋ผ๋„ LSASS๊ฐ€ 0xC0000005(์•ก์„ธ์Šค ์œ„๋ฐ˜)๋กœ ์ฃฝ๋Š”๋‹ค. ์ด๊ฒƒ์ด Sasser์˜ ์ƒ์ง•์ธ ์ข…๋ฃŒ ์นด์šดํŠธ๋‹ค์šด์„ ๋งŒ๋“ ๋‹ค.

3.2 ๊ฐ์—ผ ํ›„ ํ๋ฆ„ (์˜์‚ฌ ์ฝ”๋“œ)

on_start():
    if already_running(): exit()
    copy_self_to("%WINDIR%\\avserve2.exe")
    registry_set_run("avserve", "%WINDIR%\\avserve2.exe")
    write_log("C:\\win2.log")                  # ๊ฐ์—ผ ์‹œ๊ฐ/์นด์šดํ„ฐ ๊ธฐ๋ก
    ftp_server_listen(0.0.0.0:5554)            # ์ž๊ธฐ ๋ณต์‚ฌ๋ณธ ๋ฐฐํฌ์šฉ
    shell_listen(0.0.0.0:9996)                 # ์ต์Šคํ”Œ๋กœ์ž‡ ์…ธ์ฝ”๋“œ๊ฐ€ ๋ฐ”์ธ๋”ฉ

    for thread in 1..N:                        # ๋Œ€๋Ÿ‰ ๋™์‹œ ์Šค์บ”
        ip = pick_target_ip()                  # ์ž๊ธฐ ๋Œ€์—ญ ์šฐ์„  + ๋ฌด์ž‘์œ„
        if tcp_connect(ip, 445, timeout=short):
            send_dcerpc_overflow(ip)           # 1๋‹จ๊ณ„: LSASS ์ต์Šคํ”Œ๋กœ์ž‡
            if tcp_connect(ip, 9996):
                send("ftp -s:script.txt")      # 2๋‹จ๊ณ„: 5554์—์„œ ์ž๊ธฐ ์ž์‹  ๋ฐ›๊ธฐ
                # script.txt: open  5554 / get _up.exe / bye
    loop_forever()

์—ฌ๊ธฐ์„œ ๋ˆˆ์—ฌ๊ฒจ๋ณผ ์„ค๊ณ„๋Š” ์ž๊ธฐ ๋ฐฐํฌ ์„œ๋ฒ„๋ฅผ ์Šค์Šค๋กœ ์—ฌ๋Š” ์ž๊ธฐ์ฐธ์กฐ ๊ตฌ์กฐ๋‹ค. ์ค‘์•™ C2๋„, ์ทจ์•ฝํ•œ ์›น์„œ๋ฒ„๋„ ํ•„์š” ์—†๋‹ค. ๊ฐ์—ผ๋œ PC ํ•œ ๋Œ€๊ฐ€ ๋‹ค์Œ PC์—๊ฒŒ ํŒŒ์ผ์„ ๊ฑด๋„ค๊ณ , ๊ทธ PC๊ฐ€ ๋‹ค์‹œ ์„œ๋ฒ„๊ฐ€ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ Sasser๋Š” ์ดˆ๊ธฐ์— ํ™•์‚ฐ ์†๋„๊ฐ€ ๋งค์šฐ ๋นจ๋ž๊ณ , ๋™์‹œ์— 5554ยท9996 ํฌํŠธ ์Šค์บ”์ด๋ผ๋Š” ๊ฐ•๋ ฅํ•œ ํƒ์ง€ ์ง€๋ฌธ์„ ๋‚จ๊ฒผ๋‹ค.

3.3 ์™œ ์žฌ๋ถ€ํŒ… ๋ฃจํ”„๊ฐ€ ๋˜๋‚˜

3.4 ๋ณ€์ข… ๊ณ„๋ณด

๋ณ€์ข…๋“œ๋กญ ํŒŒ์ผํŠน์ด์ 
Sasser.Aavserve.exe์ตœ์ดˆ ํŒ๋ณธ. 4์›” 30์ผ ํ™•์‚ฐ
Sasser.B~Davserve2.exe์Šค์บ” ์Šค๋ ˆ๋“œยท๋Œ€์ƒ ๋Œ€์—ญยทํŒŒ์ผ๋ช… ๋‚œ์ˆ˜ํ™”๊ฐ€ ์กฐ๊ธˆ์”ฉ ๋ณ€๊ฒฝ, ํ™•์‚ฐ๋ ฅ ๊ฐ•ํ™”
Sasser.Eavserve2.exe์ €์ž ๊ฒ€๊ฑฐ ์งํ›„ ๋“ฑ์žฅ. ๋‹ค๋ฅธ ์›œ ์ œ๊ฑฐ ๊ธฐ๋Šฅ ํฌํ•จ(Netsky ๊ณ„์—ด์˜ ํ–‰ํƒœ)
Sasser.Favserve2.exeํ›„๊ธฐ ๋ณ€์ข…. ์ผ๋ถ€ ๋ฐฑ์‹  ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ์‹œ๋„

4. ํ”ผํ•ด ๊ทœ๋ชจ/์˜ํ–ฅ โ€” ์ˆซ์ž๋กœ ๋ณด๋Š” 2004๋…„ 5์›”

5. PoC โ€” ๋™์ž‘ ์›๋ฆฌ ์žฌํ˜„ (๊ต์œก์šฉยท๋กœ์ปฌ ๋žฉ ์ „์šฉ)

โš ๏ธ ์•ˆ์ „ ๊ทœ์น™ โ€” ์•„๋ž˜ ์ฝ”๋“œ๋Š” ๋™์ž‘ ์›๋ฆฌ ํ•™์Šต์šฉ ๋ชจ์˜ ์ฝ”๋“œ๋‹ค. ์‹ค์ œ Sasser ๋ฐ”์ด๋„ˆ๋ฆฌยท์…ธ์ฝ”๋“œยท์ต์Šคํ”Œ๋กœ์ž‡์„ ๋ณต์‚ฌยท๋ฐฐํฌํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๋ชจ๋“  ์‹ค์Šต์€ 127.0.0.1 / ๊ฐ€์ƒ ๊ฒฉ๋ฆฌ ๋žฉ์„ ์ „์ œ๋กœ ํ•œ๋‹ค. ์‹ค์ œ ์‹œ์Šคํ…œยทํƒ€์ธ ๋„คํŠธ์›Œํฌ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๋ฒ•์ด๋‹ค. 445 ํฌํŠธ ์Šค์บ”์กฐ์ฐจ ์†Œ์œ ํ•˜์ง€ ์•Š์€ ๋Œ€์—ญ์—์„œ๋Š” ๋ฒ”์ฃ„๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

PoC 1 โ€” ์Šค์บ” ํŒŒํ˜• ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ (์ „ํŒŒ 1๋‹จ๊ณ„)

์›œ์ด ์–ด๋–ป๊ฒŒ '์ฃผ๋ณ€ ๋Œ€์—ญ'์„ ํ›‘๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์™œ ๋ฐฉํ™”๋ฒฝ ํ•œ ์ค„๋กœ ๋ง‰ํžˆ๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ค€๋‹ค. ์‹ค์ œ ์ต์Šคํ”Œ๋กœ์ž‡์€ ์—†๊ณ , ๋žฉ ๋Œ€์—ญ์— ๋Œ€ํ•œ TCP ์—ฐ๊ฒฐ ์‹œ๋„๋งŒ ํ•œ๋‹ค. ์‹ค์ œ ์›œ์€ ์ˆ˜๋ฐฑ~1,000 ์Šค๋ ˆ๋“œ๋ฅผ ์ผ์ง€๋งŒ, ๋žฉ์—์„œ๋Š” 64๊ฐœ๋กœ ์ œํ•œํ•œ๋‹ค.

#!/usr/bin/env python3
# ๊ต์œก์šฉ: 127.0.0.0/24 ๊ฐ€์ƒ ๋žฉ์—์„œ "์Šค์บ” ํŒŒํ˜•"๋งŒ ์žฌํ˜„ํ•œ๋‹ค.
# ์‹ค์ œ ์ทจ์•ฝ์  ํŠธ๋ฆฌ๊ฑฐ/์…ธ์ฝ”๋“œ๋Š” ํฌํ•จํ•˜์ง€ ์•Š๋Š”๋‹ค.
import ipaddress, socket
import concurrent.futures as cf

LAB  = ipaddress.ip_network("127.0.0.0/24")   # ์†Œ์œ ํ•œ ๋žฉ ๋Œ€์—ญ๋งŒ!
PORT = 445

def probe(ip):
    s = socket.socket()
    s.settimeout(0.3)
    try:
        return str(ip), s.connect_ex((str(ip), PORT)) == 0
    finally:
        s.close()

with cf.ThreadPoolExecutor(max_workers=64) as ex:
    alive = [ip for ip, ok in ex.map(probe, LAB.hosts()) if ok]

print("๋žฉ ๋‚ด 445/TCP ์‘๋‹ต:", alive)
print("โ†’ ์ด ๋ชฉ๋ก์ด ๊ณง ์›œ์˜ '๋‹ค์Œ ๊ฐ์—ผ ํ›„๋ณด'๊ฐ€ ๋œ๋‹ค")

ํ•ด์„ค: Sasser์˜ ๋ฌด์„œ์›€์€ ์ด ๋ฃจํ”„๊ฐ€ ์‚ฌ๋žŒ ์—†์ด, ์ดˆ๋‹น ์ˆ˜๋ฐฑ ๋ฒˆ ๋ˆ๋‹ค๋Š” ์ ์ด๋‹ค. ๋ฐ˜๋Œ€๋กœ ๋ฐฉ์–ด๋Š” ๋‹จ์ˆœํ•˜๋‹ค. ์ธ๋ฐ”์šด๋“œ 445๋ฅผ ์ธํ„ฐ๋„ท์—์„œ ์ฐจ๋‹จํ•˜๋ฉด ์ด ๋ฃจํ”„๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ชป ํ•œ๋‹ค. 2004๋…„์—๋„ "๋ฐฉํ™”๋ฒฝ๋งŒ ์ œ๋Œ€๋กœ ์„ค์ •ํ•ด๋„ ๋ง‰ํ˜”๋‹ค"๋Š” ๊ฒƒ์ด ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ์˜ ๊ณต์‹ ์„ค๋ช…์ด์—ˆ๋‹ค.

PoC 2 โ€” ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ ์‹คํŒจ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ (์ทจ์•ฝ์ ์˜ ๋ณธ์งˆ)

LSASS ์˜ค๋ฒ„ํ”Œ๋กœ๋ฅผ ๊ทธ๋Œ€๋กœ ์žฌํ˜„ํ•˜๋Š” ๋Œ€์‹ , ๊ธธ์ด๋ฅผ ์‹ ๋ขฐํ•˜๋Š” ํŒŒ์„œ๊ฐ€ ์–ด๋–ค ๊ฒฐ๊ณผ๋ฅผ ๋‚ณ๋Š”์ง€ ๊ณ„์‚ฐ๋งŒ ํ•œ๋‹ค. ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ”Œ๋กœ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , ์ดˆ๊ณผ ๋ฐ”์ดํŠธ ์ˆ˜์™€ ๋ฎ์–ด์จ์งˆ ์ธ์ ‘ ํ•„๋“œ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

/* ๊ต์œก์šฉ: ์œ ์‚ฌ ํŒŒ์„œ์˜ ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ ์‹คํŒจ๋ฅผ "์‹œ๋ฎฌ๋ ˆ์ด์…˜"ํ•œ๋‹ค.
 * ์‹ค์ œ ์˜ค๋ฒ„ํ”Œ๋กœ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , ์–ด๋””์„œ ๋„˜์น˜๋Š”์ง€๋งŒ ๊ณ„์‚ฐํ•ด ์ถœ๋ ฅํ•œ๋‹ค.
 * gcc -Wall -o parser_demo parser_demo.c  (์‹คํ–‰ํ•ด๋„ ์•ˆ์ „) */
#include <stdio.h>
#include <string.h>

#define FIELD_LEN 64

typedef struct {
    char account[FIELD_LEN];
    int  authenticated;      /* ์ธ์ ‘ ํ•„๋“œ: 0์ด๋ฉด ๋ฏธ์ธ์ฆ */
} Session;

/* ํŒจ์น˜ ์ „ ์ฝ”๋“œ์˜ ํ˜•ํƒœ: ๊ธธ์ด๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฏฟ๊ณ  ๋ณต์‚ฌ */
static void parse_vulnerable(Session *s, const char *in) {
    memcpy(s->account, in, strlen(in));   /* โŒ ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ ์—†์Œ */
}

/* ํŒจ์น˜ ํ›„ ์ฝ”๋“œ์˜ ํ˜•ํƒœ: ๋‚จ๋Š” ๊ณต๊ฐ„๋งŒ ๋ณต์‚ฌ + ํ•ญ์ƒ NUL ์ข…๋ฃŒ */
static void parse_fixed(Session *s, const char *in) {
    size_t n = strlen(in);
    size_t room = sizeof(s->account) - 1;
    if (n > room) n = room;               /* โœ… ์ ˆ๋‹จ */
    memcpy(s->account, in, n);
    s->account[n] = '\0';
}

int main(void) {
    char input[512];
    memset(input, 'A', sizeof(input) - 1);
    input[sizeof(input) - 1] = '\0';

    Session s = {0};
    size_t n = strlen(input);

    printf("[vuln ] ์š”์ฒญ ๊ธธ์ด=%zu, ํ•„๋“œ ํฌ๊ธฐ=%d, ์ดˆ๊ณผ=%zu ๋ฐ”์ดํŠธ\n",
           n, FIELD_LEN, n - FIELD_LEN);
    printf("[vuln ] ์ด ์ดˆ๊ณผ๋ถ„์ด ์ธ์ ‘ ํ•„๋“œ(authenticated)๋ฅผ ๋ฎ์–ด์“ด๋‹ค\n");
#ifdef RUN_VULN_DEMO
    parse_vulnerable(&s, input);          /* ๋กœ์ปฌ ๋žฉ์—์„œ๋งŒ, ์ ˆ๋Œ€ ์„œ๋น„์Šค์— ์—ฐ๊ฒฐ ๊ธˆ์ง€ */
#endif
    parse_fixed(&s, input);
    printf("[fixed] ์ €์žฅ ๊ธธ์ด=%zu, authenticated=%d (๋ณ€์กฐ ์—†์Œ)\n",
           strlen(s->account), s.authenticated);
    return 0;
}

ํ•ด์„ค: ์ทจ์•ฝ์ ์€ 'ํ•ด์ปค์˜ ๋งˆ๋ฒ•'์ด ์•„๋‹ˆ๋ผ ํ•œ ์ค„์˜ ๊ธธ์ด ๊ฒ€์‚ฌ ๋ˆ„๋ฝ์ด๋‹ค. ํŒจ์น˜(MS04-011)๊ฐ€ ํ•œ ์ผ๋„ ๋ณธ์งˆ์ ์œผ๋กœ ์ด ๊ฒ€์‚ฌ๋ฅผ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ํ•œ ์ค„์ด ์ธํ„ฐ๋„ท์— ๋…ธ์ถœ๋œ ์ˆ˜๋ฐฑ๋งŒ ๋Œ€์— ๋™์‹œ์— ์ ์šฉ๋˜์–ด์•ผ ํ–ˆ๊ณ , 17์ผ์€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์•˜๋‹ค.

PoC 3 โ€” 2๋‹จ๊ณ„ ์ž๊ธฐ ๋ฐฐํฌ ์ฒด์ธ (5554 ํฌํŠธ์˜ ์›๋ฆฌ)

Sasser์˜ ๋…ํŠนํ•œ ์ ์€ ๊ฐ์—ผ ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ฐฐํฌ ์„œ๋ฒ„๊ฐ€ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์•„๋ž˜๋Š” ๊ทธ ๊ตฌ์กฐ๋ฅผ 127.0.0.1์—์„œ ์žฌํ˜„ํ•œ๋‹ค. ํŽ˜์ด๋กœ๋“œ๋Š” ์‹คํ–‰ ํŒŒ์ผ์ด ์•„๋‹ˆ๋ผ ๋ฌดํ•ดํ•œ ํ…์ŠคํŠธ ํŒŒ์ผ์ด๋ฉฐ, ์‹ค์ œ ์›œ์€ FTP๋ฅผ ์ผ์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ๊ตฌํ˜„ ํŽธ์˜์ƒ HTTP๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

# ๊ต์œก์šฉ: "๋‹ค์Œ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ด์ „ ํ˜ธ์ŠคํŠธ์—๊ฒŒ์„œ ์ž์‹ ์„ ๋ฐ›์•„๊ฐ„๋‹ค"๋Š”
# 2๋‹จ๊ณ„ ์ „๋‹ฌ ๊ตฌ์กฐ๋งŒ 127.0.0.1์—์„œ ์žฌํ˜„ํ•œ๋‹ค. ํŽ˜์ด๋กœ๋“œ๋Š” ๋ฌดํ•ดํ•œ ํ…์ŠคํŠธ.
import hashlib, http.server, os, socketserver, threading, urllib.request

os.makedirs("/tmp/lab", exist_ok=True)
stage2 = "/tmp/lab/13337_up.exe"
with open(stage2, "w") as f:
    f.write("EDUCATIONAL-ONLY: this is not an executable\n")

os.chdir("/tmp/lab")
srv = socketserver.TCPServer(
    ("127.0.0.1", 5554),                 # ์‹ค์ œ Sasser์˜ FTP ํฌํŠธ์™€ ๋™์ผ
    http.server.SimpleHTTPRequestHandler)
threading.Thread(target=srv.serve_forever, daemon=True).start()

data = urllib.request.urlopen(
    "http://127.0.0.1:5554/13337_up.exe", timeout=3).read()
print("2๋‹จ๊ณ„ ์ˆ˜์‹  ๋ฐ”์ดํŠธ:", len(data))
print("sha256(์•ž 16์ž):", hashlib.sha256(data).hexdigest()[:16])
print("โ†’ ์‹ค์ œ ์›œ์€ ์ด ํŒŒ์ผ์„ ์ฆ‰์‹œ ์‹คํ–‰ํ–ˆ๋‹ค")
srv.shutdown()

ํ•ด์„ค: ๋ฐฉ์–ด ๊ด€์ ์—์„œ ์ด ๊ตฌ์กฐ๋Š” ์•„์›ƒ๋ฐ”์šด๋“œ ํƒ์ง€์˜ ๊ธฐํšŒ๋‹ค. ๋‚ด๋ถ€ ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ฐ‘์ž๊ธฐ 5554๋ฅผ ๋ฆฌ์Šค๋‹ํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ๋‚ด๋ถ€ ํ˜ธ์ŠคํŠธ์˜ 5554๋กœ ์ ‘์†ํ•˜๋ฉด ๊ทธ๊ฒƒ์€ ์ •์ƒ ์—…๋ฌด๊ฐ€ ์•„๋‹ˆ๋‹ค. Sasser ์‹œ๋Œ€์—๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ์—…์ด ์•„์›ƒ๋ฐ”์šด๋“œ์กฐ์ฐจ ๋ณด์ง€ ์•Š์•˜์ง€๋งŒ, ์˜ค๋Š˜๋‚  EDR์€ ์ด ๋‘ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ์žก๋Š”๋‹ค.

PoC 4 โ€” ํ–‰์œ„ ๊ธฐ๋ฐ˜ ํƒ์ง€ ๊ทœ์น™ (๋ฐฉ์–ด)

์‹œ๊ทธ๋‹ˆ์ฒ˜(ํŒŒ์ผ ํ•ด์‹œ)๋Š” ๋ณ€์ข…๋งˆ๋‹ค ๋ฐ”๋€๋‹ค. ์‚ด์•„๋‚จ๋Š” ๊ฒƒ์€ ํ–‰์œ„๋‹ค. Sasser ๊ณ„์—ด์„ ์žก๋Š” ์ตœ์†Œ ๊ทœ์น™ ์ง‘ํ•ฉ์„ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๋กœ ์‹œํ—˜ํ•œ๋‹ค.

# ๊ต์œก์šฉ ํƒ์ง€: ํ•ฉ์„ฑ ์ด๋ฒคํŠธ์—์„œ Sasser์˜ 4๊ฐ€์ง€ ์ง€๋ฌธ์„ ์ฐพ๋Š”๋‹ค.
events = [
    {"host": "lab-01", "dst_port": 445, "syn_per_min": 640},
    {"host": "lab-01", "listen_port": 5554},
    {"host": "lab-02", "dst_port": 9996, "direction": "outbound"},
    {"host": "lab-02", "file": "avserve2.exe", "path": "C:\\Windows"},
    {"host": "lab-03", "run_key": "avserve", "syn_per_min": 3},
]

def scan_flood(e):
    return e.get("dst_port") == 445 and e.get("syn_per_min", 0) > 200

def ftp_listener(e):
    return e.get("listen_port") == 5554

def shell_callback(e):
    return e.get("dst_port") == 9996 and e.get("direction") == "outbound"

def dropped_binary(e):
    f = e.get("file", "").lower()
    return f.startswith("avserve") or (f.endswith("_up.exe") and f[:5].isdigit())

RULES = [
    ("SMB ์Šค์บ” ํญ์ฃผ (์›œ ์ „ํŒŒ 1๋‹จ๊ณ„)", scan_flood),
    ("5554 ๋ฆฌ์Šค๋„ˆ (์ž๊ธฐ ๋ฐฐํฌ ์„œ๋ฒ„)",  ftp_listener),
    ("9996 ์•„์›ƒ๋ฐ”์šด๋“œ (์ต์Šคํ”Œ๋กœ์ž‡ ์…ธ)", shell_callback),
    ("avserve/_up.exe ๋“œ๋กญ (์ƒ์ฃผ)",   dropped_binary),
]

for e in events:
    for name, rule in RULES:
        if rule(e):
            print(f"[ALERT] {e['host']}: {name}")

ํ•ด์„ค: ์‹ค์ œ ์šด์˜์—์„œ๋Š” ์—ฌ๊ธฐ์— HKLM\Software\Microsoft\Windows\CurrentVersion\Run์˜ avserve ๊ฐ’, C:\win.logยทwin2.log ์ƒ์„ฑ, ์งง์€ ์‹œ๊ฐ„ ๋‚ด ๋‹ค์ˆ˜ ํ˜ธ์ŠคํŠธ์˜ LSASS ํฌ๋ž˜์‹œ(์ด๋ฒคํŠธ ID 1000/7031)๋ฅผ ์ƒ๊ด€ ๋ถ„์„์œผ๋กœ ๋ฌถ๋Š”๋‹ค. ๋‹จ์ผ ์ด๋ฒคํŠธ๋Š” ์˜คํƒ์ด ๋งŽ์ง€๋งŒ, ์Šค์บ” ํญ์ฃผ + 5554 + LSASS ํฌ๋ž˜์‹œ๊ฐ€ ๊ฐ™์€ ํ˜ธ์ŠคํŠธ์—์„œ ๊ฒน์น˜๋ฉด ํ™•์‹ ๋„๊ฐ€ ๊ธ‰์ƒ์Šนํ•œ๋‹ค.

6. ๋ฐฉ์–ด ๋ฐฉ๋ฒ• โ€” 2004๋…„์˜ ๋‹ต, ๊ทธ๋ฆฌ๊ณ  ์˜ค๋Š˜์˜ ๋‹ต

6.1 ์ฆ‰์‹œ ์กฐ์น˜(๋‹น์‹œ ๊ธฐ์ค€)

6.2 ์˜ค๋Š˜๋‚ ์˜ ๊ด€์ 

7. ๊ตํ›ˆ โ€” Sasser๊ฐ€ ๋‚จ๊ธด ๋„ค ๊ฐ€์ง€

์ถœ์ฒ˜ ๋ฐ ํ•จ๊ป˜ ์ฝ๊ธฐ

โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ