케이블 여섯 가닥, 파우치는 한 달 전 그대로였다
9월 22일, 8월 21일에 처음 적어 둔 악성코드 배포 주소에서 다시 파일이 내려왔습니다. 맨 앞 설치 스크립트는 한 달 전과 한 글자도 다르지 않았는데, CPU 종류별 실행파일 여섯 개는 전부 처음 보는 파일이었습니다. 그중 다섯 개의 이름은 우리가 전에 압축을 풀어서야 알아낸 이름과 똑같았습니다.

친구 집에 놀러 갔는데 휴대폰 배터리가 5% 남았다고 해 봅시다. 충전기를 빌려야 합니다. 그런데 친구 휴대폰 충전 단자가 내 것과 같을까요? C타입일 수도 있고, 8핀일 수도 있고, 오래된 5핀일 수도 있습니다.
그래서 어떤 사람들은 가방에 케이블 파우치를 넣고 다닙니다. 작은 주머니 하나에 단자 모양이 다른 케이블을 종류별로 넣어 둡니다. 상대 기계가 뭔지 몰라도 됩니다. 하나씩 꽂아 보면 어느 하나는 맞으니까요.
어제 우리 서버에 누군가 이런 파우치를 들고 왔습니다. 안에는 여섯 가닥이 들어 있었습니다. 그런데 이 파우치는 한 달 전에 한 번 본 파우치였습니다. 주머니는 그때와 똑같았는데, 케이블은 여섯 가닥 모두 새것이었습니다.
오늘은 이 파우치 이야기를 합니다.
먼저, 우리 서버는 일부러 열어 둔 집입니다
사실 우리는 허니팟을 운영합니다. 허니팟은 일부러 허술하게 열어 두고 누가 들어와 무엇을 하는지 지켜보는 미끼 서버입니다. 그래서 아래 이야기는 진짜 피해가 아니라 관찰 기록입니다. 서버는 두 대입니다. 첫 번째(센서 01)는 문이 실제로 열리는 서버입니다. 두 번째(센서 02)는 누가 문을 두드렸는지만 적는 얕은 서버입니다.
사실
어제의 주인공은 ATK-DD0862 입니다. 출발지 IP 는 87.58.x.x 로 가려서 적습니다. 별칭은 우리 기록에 처음 나온 이름입니다. 이 방문자는 텔넷으로 들어왔습니다. 텔넷은 멀리 있는 기계에 글자로 명령을 보내는 오래된 원격 접속 방식입니다. 오가는 내용이 암호화되지 않습니다. 오늘날에는 주로 공유기나 카메라 같은 작은 장비에 남아 있습니다. 포트는 2223 번이었고, 로그인에 성공했습니다.
19.30초, 파우치를 여는 데 걸린 시간
사실 로그인하고 나간 때까지 19.30초가 걸렸습니다. 그동안 명령 11개를 쳤습니다. 1.75초에 명령 하나꼴입니다. 사람이 손으로 치기는 어려운 속도입니다. 그 사이 파일 8개를 내려받았습니다. 2.4초에 하나씩입니다. 우리 분류기는 이 세션의 행동에 세 가지 이름을 붙였습니다. 파일 다운로드 → 실행 권한 부여 → 다운로드 후 실행 순서입니다.
사실
8개 중 맨 앞은 kla.sh 라는 셸 스크립트입니다. 셸 스크립트는 명령 여러 줄을 한 파일에 모아 둔 것입니다. 실행하면 적힌 명령이 차례로 돌아갑니다. 크기는 3,013바이트입니다. 영어로 치면 A4 한 장 남짓한 글자 수입니다.
추정
이런 공격에서 맨 앞 스크립트는 보통 파우치 역할을 합니다. 뒤따르는 실행파일들을 챙겨 오고 차례로 꽂아 보게 하는 주머니입니다. 다만 kla.sh 안에 무엇이 적혀 있었는지는 우리 재료에 없습니다. 이건 비슷한 구조에 비춰 본 해석입니다.
사실 나머지 중 여섯 개가 실행파일, 즉 케이블입니다. 리눅스에서 쓰는 ELF 라는 형식의 프로그램입니다. 여섯 개를 모두 합치면 1,092,512바이트, 1메가바이트 남짓입니다. 스마트폰 사진 한 장보다 작습니다.
왜 한 번에 여섯 가닥일까
사실 컴퓨터의 두뇌인 CPU 는 종류가 여러 가지입니다. 충전 단자 모양이 다르듯이, CPU 종류가 다르면 프로그램도 거기에 맞춰 따로 만들어야 돌아갑니다. 어제 내려온 여섯 개는 CPU 종류가 제각각이었습니다. 표의 가운데 칸을 보세요.
| 파일 이름 | 어떤 CPU 용인가 | 크기 | 젠더가 필요한가 |
|---|---|---|---|
px86 |
Intel 80386 (x86) | 133,292바이트 | 아니요 (정적 링크) |
pmips |
MIPS-I · 빅 엔디언 | 244,740바이트 | 아니요 (정적 링크) |
pmpsl |
MIPS-I · 리틀 엔디언 | 248,836바이트 | 아니요 (정적 링크) |
parm |
ARM | 182,976바이트 | 아니요 (정적 링크) |
parm5 |
ARM | 83,344바이트 | 예 (동적 링크) |
parm6 |
ARM EABI4 | 199,324바이트 | 아니요 (정적 링크) |
사실 x86, MIPS, ARM. 세 계열을 한꺼번에 챙겼습니다. MIPS 는 두 벌입니다. 엔디언은 CPU 가 숫자를 앞에서부터 읽느냐 뒤에서부터 읽느냐의 차이입니다. 같은 MIPS 라도 방향이 다르면 다른 케이블이 필요합니다.
사실
오른쪽 칸의 정적 링크는 필요한 부품을 파일 안에 다 넣어 둔 상태입니다. 케이블 하나로 끝나고 젠더가 필요 없습니다. 여섯 중 다섯이 이렇습니다. parm5 하나만 동적 링크입니다. 대상 장비에 /lib/ld-uClibc.so.0 라는 부품이 미리 있어야 돌아갑니다. 젠더를 끼워야 꽂히는 케이블인 셈입니다. 여섯 개 모두 안쪽의 설명 메모를 지운 상태(stripped)이기도 합니다.
추정 방문자는 우리 서버가 어떤 CPU 인지 몰랐을 겁니다. 그래서 여섯 가닥을 다 들고 왔을 것입니다. 그리고 이 구성은 일반 서버보다 공유기·CCTV 같은 작은 장비에 맞는 쪽입니다. 그런 장비를 봇넷에 끌어들이려는 구성과 맞아떨어집니다. 봇넷은 주인 모르게 원격 조종당하는 기계들의 무리입니다. 정적 링크 다섯 개는 CPU 만 맞으면 어느 리눅스에서든 돌아갑니다.
파우치는 그대로, 케이블만 새것
사실
여기서부터가 오늘의 핵심입니다. 이 파일들은 모두 hxxp://176[.]65[.]139[.]196/bins/ 에서 받아 왔습니다. 이 주소는 우리 기록에 8월 21일에 딱 한 번 나온 곳입니다. 그날 글의 제목이 “처음 보는 주소에서 파일 세 개”였습니다. 아카이브 기준으로 32일 만에 다시 나타났습니다.
사실 파일마다 해시라는 값이 있습니다. 파일 내용 전체로 계산한 고유 번호입니다. 한 글자만 달라져도 완전히 다른 값이 나옵니다. 케이블마다 찍힌 일련번호라고 생각하면 됩니다. 한 달 전과 어제의 일련번호를 나란히 놓아 봤습니다. 맨 오른쪽 칸을 보세요.
| 파일 | 8월 21일 | 9월 22일 (어제) | 같은가 |
|---|---|---|---|
kla.sh (파우치) |
3,013바이트 · bb36568c… |
3,013바이트 · bb36568c… |
똑같음 |
px86 |
133,452바이트 · 979bd80a… |
133,292바이트 · 2461a317… |
다름 (160바이트 작아짐) |
pmips |
244,420바이트 · ed6bae21… |
244,740바이트 · 41a3941b… |
다름 (320바이트 커짐) |
pmpsl · parm · parm5 · parm6 |
(없었음) | 새로 등장 | 이 주소에서 처음 보는 이름 |
사실
파우치 kla.sh 는 32일 동안 한 비트도 바뀌지 않았습니다. 반대로 케이블 여섯 가닥의 일련번호는 전부 처음 보는 값입니다. 아카이브 29일치(8/16~9/20)를 다 뒤져도 없습니다. 이름이 같은 px86 도 크기가 0.1% 남짓 달라졌고, 일련번호는 완전히 바뀌었습니다. 8월 21일에 두 가닥이던 파우치가 어제는 여섯 가닥이 됐습니다.
추정
같은 자리에서 파우치는 두고 케이블만 새로 만들어 올리는 모습입니다. 우리 기록에 이런 모습이 나온 게 이번이 세 번째입니다. 8월 24일(31[.]77 계열)과 9월 20일(160[.]119[.]66[.]206 의 net.x86_64)에도 있었습니다.
추정 이게 왜 중요할까요? 8월 21일의 일련번호 목록으로 문단속을 했다고 해 봅시다. 어제 들어온 케이블 여섯 가닥은 하나도 걸리지 않습니다. 파우치 하나만 걸립니다. 반대로 **“이 가게에서 온 물건은 받지 않는다”**는 규칙이었다면 어떨까요? 주소가 기록된 일곱 개가 모두 걸립니다. 일련번호는 한 달이면 다 바뀝니다. 파우치를 받아 오는 가게 주소는 그대로였습니다.
이름표는 이미 알고 있었다
사실
재미있는 점이 하나 더 있습니다. 우리는 전에 UPX 로 압축된 악성코드를 풀어 본 적이 있습니다. UPX 는 실행파일을 꽁꽁 싸매 부피를 줄이는 도구입니다. 싸맨 상태에서는 겉에 주소가 하나도 보이지 않습니다. 비닐을 뜯어야 안에 든 케이블의 규격 이름표가 보이는 상자와 같습니다. 그렇게 뜯어서만 얻은 이름이 12개 있습니다. 모두 31[.]77[.]227[.]121/bins/ 아래의 파일입니다.
parm · parm5 · parm6 · parm64 · parm7 · pm68k · pmips · pmpsl · pppc · psh4 · pspc · x86_64
사실
어제 여섯 가닥 중 다섯 가닥의 이름이 이 목록과 글자까지 같습니다. parm · parm5 · parm6 · pmips · pmpsl 입니다. 겹치지 않는 건 px86 하나입니다. 목록에는 x86_64 가 있습니다. 8월 21일에는 겹치는 이름이 pmips 하나뿐이었습니다.
추정 겉만 보고 모은 기록이었다면 어제 여섯 개는 “처음 보는 파일 여섯 개”로만 남았을 겁니다. 상자를 뜯어 이름표 규칙을 미리 알아 두었기 때문에 알아볼 수 있었습니다. 가게 주소가 다른데도 같은 계열의 이름 붙이기 방식이라는 걸 첫눈에 알았습니다.
사실 선을 두 개 긋겠습니다. 첫째, 어제의 주소 일곱 개는 세션에서 그대로 보였습니다. 상자를 뜯어서 얻은 게 아닙니다. 뜯어 본 경험이 준 건 주소가 아니라 이름표 규칙입니다. 둘째, 이름 규칙이 같다는 건 같은 계열의 공개된 제작 도구를 썼다는 뜻일 뿐입니다. 같은 사람이나 같은 조직이라는 뜻이 아닙니다. 같은 브랜드 케이블을 쓴다고 같은 사람은 아니니까요.
시간 순서로 늘어놓으면
어제 첫 번째 서버에서 벌어진 일을 시간 순서로 놓으면 이렇습니다. 17:02 의 두 줄과 그 아래 검체 줄을 눈여겨보세요. 파우치 하나를 여는 데 20초가 안 걸렸습니다.
- 사실 ATK-040C4F(222.86.x.x) 텔넷 로그인 성공. 91.94초 · 명령 31개 · 의도 3개(다운로드 후 실행 · 실행 권한 부여 · 파일 다운로드). 다운로드 0건 · 기록 촘촘함 13. 저장된 파일이 없어 오늘의 주제가 아니다
- 사실 ATK-DD41EC(116.92.x.x) 텔넷 로그인 성공. 9.58초 · 명령 28개 · 다운로드 11건, 11건 모두 1바이트 빈 파일(01ba4719…). 의도는 '방어 무력화' 하나이고 기록 촘촘함 42 로 오늘 최고. 하루 전체의 '방어 무력화' 집계가 1회라 그 1회가 이 세션으로 보인다(개수가 맞는다는 것에 근거한 추정). 9/20 에도 같은 별칭이 9.17초 · 명령 28개였다
- 사실 오늘의 주제 세션 시작. ATK-DD0862(87.58.x.x) 텔넷(포트 2223) 로그인 성공. 아카이브에 없던 별칭. 텔넷이라 접속 프로그램 표식이 빈 문자열이다
- 사실 19.30초 동안 명령 11개 · 다운로드 8건. 의도 3개(파일 다운로드 · 실행 권한 부여 · 다운로드 후 실행). 기록 촘촘함 37. 화면 녹화됨(내용은 재료에 없음). 이 별칭만 배달한 파일의 개수 합이 8 이라 다운로드 수와 맞는다
- 사실 hxxp://176[.]65[.]139[.]196/bins/kla.sh · 3,013바이트 Bourne-Again 셸 스크립트 · bb36568c…. 8/21 브리프에 같은 URL · 같은 크기 · 같은 해시가 있다. 8/21 에서 9/22 까지 32일 동안 바뀌지 않았다
- 사실 모두 176[.]65[.]139[.]196/bins/ 에서 받았다. px86 133,292B ELF32 LSB Intel 80386 정적 · pmips 244,740B ELF32 MSB MIPS-I 정적 · pmpsl 248,836B ELF32 LSB MIPS-I 정적 · parm 182,976B ELF32 LSB ARM 정적 · parm5 83,344B ELF32 LSB ARM 동적(/lib/ld-uClibc.so.0) · parm6 199,324B ELF32 LSB ARM EABI4 정적. 여섯 개 모두 stripped, 합계 1,092,512바이트
- 사실 8/21 같은 URL 의 px86 은 133,452B(979bd80a…), pmips 는 244,420B(ed6bae21…). 오늘 px86 은 160바이트 작아졌고 pmips 는 320바이트 커졌으며 해시는 둘 다 다르다. 8/21 에 두 종류였던 아키텍처가 오늘 여섯 벌. pmpsl · parm · parm5 · parm6 은 이 호스트에서 오늘 처음 보는 파일 이름
- 사실 9바이트 ASCII 텍스트 1건(0dc95fb4…, URL 미기록). 9/17 에는 ATK-A593DF, 9/20 에는 ATK-CE432E 가 남긴 것과 같은 해시. 오늘은 ATK-DD0862 가 남겼다
- 추정 같은 경로에 로더는 두고 실행파일만 새로 빌드해 올리는 패턴은 8/24(31[.]77 계열) · 9/20(160[.]119[.]66[.]206 net.x86_64)에 이어 세 번째. 8/21 해시로 만든 차단 목록은 오늘 실행파일 여섯 개 중 어느 것도 잡지 못하고 kla.sh 하나만 잡는다. URL · 호스트 기준 규칙은 주소가 기록된 파일을 모두 잡는다
- 추정 9/17 에는 같은 /24 대역의 .206 이 kworkerd-* 이름 체계로 파일을 내보냈다. 오늘 .196 은 8/21 의 'bins/p+아키텍처' 체계로 돌아왔다. 두 호스트가 번갈아 쓰이는지, 동시에 운영되는지, 관계가 없는지 알 수 없다. 아카이브에 빠진 날이 있어 '32일 동안 쉬었다'고도 말할 수 없다
- 사실 ATK-BDB53E(160.119.x.x) 텔넷 세션 A: 7.01초 · 명령 7개 · 다운로드 2건. 2.38초 뒤 시작한 세션 B: 4.67초 · 명령 2개 · 다운로드 2건, A 가 끝난 0.04초 뒤 종료. 검체 kla.sh(39be6853…, 3,241B) · net.x86_64(2cebccdc…, 192,328B)는 둘 다 9/20 과 같은 해시. 9/15 · 9/17 · 9/20 에 이어 네 번째
- 사실 세션 829 · 고유 출발지 207 · 로그인 시도 542 · 명령 790 · 화면 녹화 302. SSH 560(포트 2222) · 텔넷 269(포트 2223). 텔넷은 세션의 32.4%인데 주요 세션 5건은 모두 텔넷. 의도 분류 합 491 로 명령 790개와 299 차이
- 사실 389바이트 공개키(a8460f44…)를 남긴 출발지 41 → 24곳. 345gs5662d34 조합 40 → 23곳. libssh_0.9.6 표식(f555226d…) 41 → 24곳. SSH 키 심기 의도 43 → 24회. 9/20 에 나란히 튀었던 네 값이 나란히 내려왔다
- 사실 세션 45,461 · 고유 출발지 461. VNC 33,287(73.2%, 출발지 214) · RDP 11,698(출발지 119) · SMB 250 · MSSQL 61 · LDAP 35 · ADB 130. 저상호작용 센서라 로그인 성공 · 명령 · 자격증명은 존재하지 않는다
- 사실 'Administr' 5,159회 · 'Admin' 5,151회, 합쳐 RDP 접촉의 88.1%. 'Administr' 는 아카이브 최대(9/20, 94회)의 약 54.9배, 'Admin' 은 9/20 66회의 약 78.1배. 9/10~9/20 에 반복되던 'mstsc' 는 오늘 목록에 없다
사실
기록이 가장 촘촘한 다섯 세션은 모두 텔넷이었습니다. 텔넷은 어제 세션의 3분의 1(32.4%)뿐입니다. 그런데 파일을 받아 간 쪽은 전부 텔넷이었습니다. 다른 세션을 주제로 고르지 않은 이유도 적어 둡니다. ATK-DD41EC 는 기록 촘촘함이 1위(42)입니다. 하지만 1바이트 빈 파일 11개를 받는 모양이 8월 18일부터 아홉 번 반복된 계열입니다. ATK-BDB53E 는 네 번째 방문이고 파일도 9월 20일과 같습니다. ATK-040C4F 는 명령이 31개인데 저장된 파일이 없습니다.
어제 나온 값 — 받아 적을 것
방어에 쓰실 수 있게 값을 그대로 옮깁니다. 값을 누르면 복사됩니다. 주소는 실수로 접속되지 않게 변형(디팽)해 두었습니다. http 대신 hxxp, 점 대신 [.] 를 쓴 형태입니다. 그대로 두고 쓰세요. 둘째 줄부터 일곱째 줄까지가 어제 처음 본 일련번호입니다.
bb36568c1f0a4f4d604cc67f8692506291eb1ffd217a451ffc846c94daa09440kla.sh · 3,013바이트 Bourne-Again 셸 스크립트 · 출처 ATK-DD0862 · 8/21 과 같은 해시로 32일 동안 변하지 않았다2461a31775cc11e16548a2e47c5a1afd7bddb57b97d2247cc02bb4c5c63da498px86 · 133,292바이트 ELF32 i386 정적 링크 · 아카이브에 없는 해시 · 8/21 같은 URL 은 133,452바이트 · 979bd80a…41a3941bce8b84117e260d93b8a04087a844e9dc36fdd14d18a73d18e7fc8fb4pmips · 244,740바이트 ELF32 MSB MIPS-I 정적 링크 · 아카이브에 없는 해시 · 8/21 같은 URL 은 244,420바이트 · ed6bae21… · 압축을 풀어 얻은 이름 목록의 pmips 와 같은 이름82d0ca43bf8179a90e49a733b05374dad2461249acaea02d254e00a45eb83662pmpsl · 248,836바이트 ELF32 LSB MIPS-I 정적 링크 · 아카이브에 없는 해시 · 압축을 풀어 얻은 이름 목록의 pmpsl 과 같은 이름6e028a69d35e03461e8b272356d507bc82c68dad2bfb5ee8b81ea4f334703fefparm · 182,976바이트 ELF32 LSB ARM 정적 링크 · 아카이브에 없는 해시 · 압축을 풀어 얻은 이름 목록의 parm 과 같은 이름13e3e1310dd9e9210ed937a651361be16b554be2d20ce5ae06b1dcf610dda603parm5 · 83,344바이트 ELF32 LSB ARM 동적 링크(uClibc) · 여섯 중 유일한 동적 링크 · 아카이브에 없는 해시 · 압축을 풀어 얻은 이름 목록의 parm5 와 같은 이름7aa4efe57da57809d1ed2eab48d4def41165af50e4f1576a11ce867b237cfea8parm6 · 199,324바이트 ELF32 LSB ARM EABI4 정적 링크 · 아카이브에 없는 해시 · 압축을 풀어 얻은 이름 목록의 parm6 과 같은 이름0dc95fb4077cce0bff19aa1a77109d059dff6503bbf6c1b0dd2f41fc0a4c88e79바이트 ASCII 텍스트 · URL 미기록 · 9/17 · 9/20 에 다른 별칭이 남긴 것과 같은 해시hxxp://176[.]65[.]139[.]196/bins/kla.sh위 셸 스크립트의 유포지 · 8/21 과 같은 URLhxxp://176[.]65[.]139[.]196/bins/px86위 px86 의 유포지 · 8/21 과 같은 URL, 다른 해시hxxp://176[.]65[.]139[.]196/bins/pmips위 pmips 의 유포지 · 8/21 과 같은 URL, 다른 해시hxxp://176[.]65[.]139[.]196/bins/pmpsl위 pmpsl 의 유포지 · 이 호스트에서 처음 보는 이름hxxp://176[.]65[.]139[.]196/bins/parm위 parm 의 유포지 · 이 호스트에서 처음 보는 이름hxxp://176[.]65[.]139[.]196/bins/parm5위 parm5 의 유포지 · 이 호스트에서 처음 보는 이름hxxp://176[.]65[.]139[.]196/bins/parm6위 parm6 의 유포지 · 이 호스트에서 처음 보는 이름사실
열다섯 줄을 다시 보세요. 해시 줄은 여덟 개이고, 그중 여섯이 새것입니다. 주소 줄 일곱 개는 앞부분 hxxp://176[.]65[.]139[.]196/bins/ 가 전부 같습니다. 일련번호는 매번 새로 외워야 합니다. 가게 주소는 한 줄로 끝납니다.
이 비밀번호 쓰고 계십니까
사실 어제 첫 번째 서버의 로그인 시도는 542회였습니다. 하루로 나누면 2분 40초에 한 번꼴로 누군가 문고리를 돌려 본 셈입니다. 출발지는 207곳이었습니다. 한 곳당 2.6번꼴입니다.
사실 시도된 아이디·비밀번호 조합 중 이 글에 옮기는 건 13종뿐입니다. 서로 다른 IP 세 곳 이상에서 반복된 조합만 원문을 적는 게 우리 규칙입니다. 이 기준에 못 미친 366종은 개수만 세고 값은 적지 않습니다. 한 곳에서만 나온 조합은 어디선가 새어 나간 누군가의 진짜 계정일 수 있기 때문입니다. 아래 13종은 반대로 여러 곳이 똑같이 넣어 본, 누구의 것도 아닌 흔한 값입니다. 첫 줄과 넷째 줄을 보세요.
| 아이디 | 비밀번호 | 서로 다른 출발지 |
|---|---|---|
| 345gs5662d34 | 345gs5662d34 | 23곳 (9/20 은 40곳) |
| admin | admin | 13곳 (26회 · 곳당 2회) |
| root | 123456 | 7곳 |
| root | (빈칸) | 6곳 (22회 · 곳당 약 3.7회) |
| root | 3245gs5662d34 | 5곳 |
| root | 12345 | 4곳 |
| (빈칸) | (빈칸) | 4곳 |
| root | abcd1234 | 3곳 |
| root | 1234 | 3곳 |
| admin | password | 3곳 |
| root | admin | 3곳 |
| admin | admin123 | 3곳 |
| support | support | 3곳 |
사실
첫 줄의 이상한 문자열은 9월 20일에 40곳이었다가 어제 23곳으로 줄었습니다. 비밀번호 칸이 아예 빈 root 는 6곳이 22번 넣어 봤습니다. 한 곳이 3.7번씩입니다. 표에서 곳당 반복이 가장 많습니다.
어제 하루 전체
사실 문이 실제로 열리는 첫 번째 서버의 하루 집계입니다. 오른쪽 칸을 함께 보세요. 숫자 하나만으로는 크기가 잘 안 잡힙니다.
| 항목 | 9월 22일 | 견줄 것 |
|---|---|---|
| 세션 | 829건 | 1분 44초에 한 번 |
| 고유 출발지 | 207곳 | 한 곳당 평균 4.0세션 |
| 로그인 시도 | 542회 | 2분 40초에 한 번 · 한 곳당 2.6회 |
| 명령 | 790개 | 1분 49초에 하나 |
| 포트 2222 (SSH) | 560세션 | 전체의 67.6% |
| 포트 2223 (텔넷) | 269세션 | 32.4% — 그런데 주요 세션 5건은 모두 텔넷 |
사실 서버 안에서 친 명령을 종류별로 나누면 이렇습니다.
| 무엇을 하려 했나 | 횟수 |
|---|---|
| 정찰 — 시스템 살펴보기 | 188회 |
| 실행 권한 부여 | 177회 |
| 파일 다운로드 | 39회 |
| 다운로드 후 실행 | 37회 |
| 흔적 삭제 | 25회 |
| 지속성 — SSH 키 심기 | 24회 |
| 방어 무력화 | 1회 |
사실
일곱 줄을 더하면 491입니다. 명령 790개와 299개 차이가 납니다. 그 299개가 무엇인지는 재료에 설명이 없습니다. ’SSH 키 심기’는 서버에 비밀번호 없이 다시 들어올 수 있는 열쇠를 몰래 등록해 두는 일입니다. 9월 20일에 43회로 튀었다가 어제 24회로 내려왔습니다. 그 열쇠 파일(389바이트 공개키 a8460f44…)을 남긴 출발지도 41곳에서 24곳으로 줄었습니다. 이틀 전 나란히 튀었던 네 숫자가 나란히 내려왔습니다.
사실 두 번째 서버(센서 02)는 문을 열어 주지 않고 누가 두드렸는지만 적습니다. 그래서 로그인 성공도, 명령도, 자격증명도 여기엔 없습니다. 어제는 45,461건이 461곳에서 왔습니다. 1.9초에 한 번입니다. 화면 공유(VNC)가 33,287건으로 73.2%입니다. 원격 데스크톱(RDP)은 11,698건입니다.
사실
원격 데스크톱으로 접속할 때 상대는 스스로 이름표(쿠키)를 적어 보냅니다. 어제는 Administr 가 5,159번, Admin 이 5,151번이었습니다. 둘을 합치면 RDP 의 **88.1%**입니다. Administr 는 우리 기록에서 가장 많았던 9월 20일(94번)의 약 54.9배입니다. Admin 은 9월 20일 66번의 약 78.1배입니다. 9월 10일부터 20일까지 꾸준히 보이던 mstsc 는 어제 목록에서 사라졌습니다. 이름표는 상대가 마음대로 적는 값이라 그대로 믿을 수는 없습니다.
공격자가 쓴 수법을 국제 분류표에 대응시키면
MITRE ATT&CK 은 공격 수법마다 번호를 붙여 둔 국제 목록입니다. 어제 본 행동을 그 번호에 맞추면 이렇습니다. ID 를 누르면 원문 설명으로 갑니다. 우리 말을 그대로 믿지 말고 직접 확인하시라고 링크를 겁니다.
- T1110.001Brute Force: Password Guessing — 로그인 시도 542회, 인용 가능한 조합 13종추정
- T1078.001Valid Accounts: Default Accounts — 주제 세션 로그인 성공, 인용 가능한 조합이 기본값 계열추정
- T1059.004Command and Scripting Interpreter: Unix Shell — 텔넷 셸에서 명령 11개, 셸 스크립트 kla.sh추정
- T1105Ingress Tool Transfer — '파일 다운로드' 의도, 검체 8건추정
- T1222.002File and Directory Permissions Modification: Linux and Mac — '실행 권한 부여' 의도추정
- T1027.002Obfuscated Files or Information: Software Packing — 전에 풀어 본 UPX 검체에 근거. 오늘 ELF 6종은 압축 여부가 기록에 없어 오늘 파일이 압축됐다고는 말할 수 없다추정
- T1098.004Account Manipulation: SSH Authorized Keys — 하루 전체 집계(SSH 키 심기 24회, 공개키 24곳). 주제 세션과는 관계없다추정
- T1070Indicator Removal — 하루 전체 집계 흔적 삭제 25회. 주제 세션과는 관계없다추정
- T1562Impair Defenses — 하루 전체 1회(ATK-DD41EC 로 보임). 명령 원문이 없어 하위 기법은 붙이지 않는다추정
사실 아홉 줄 모두 **[추정]**입니다. 우리 손에 있는 건 명령의 ’의도 분류 결과’와 횟수, 파일의 이름·크기·종류까지입니다. 명령 원문도 파일 내용도 없습니다. 분류표에 맞추는 건 늘 해석입니다. 그리고 아래 세 줄(T1098.004 · T1070 · T1562)은 어제의 파우치와 상관없는 하루 전체 이야기입니다.
전에 이런 모양이 있었다
추정 Mirai 봇넷과 그 파생 계열 (2016~). 텔넷 기본 자격증명으로 들어간 뒤
/bins/같은 웹 경로에서 CPU 종류별 실행파일을 여러 벌 받는 구조입니다. 그중 맞는 것이 실행되게 합니다. 어제 한 세션이 x86·MIPS(두 방향)·ARM 을 한꺼번에 받은 모습과 맞습니다. 다만 소스코드가 2016년에 공개돼서, 서로 관계없는 운영자들도 같은 이름 규칙을 씁니다. (출처 유형: 미국 법무부 기소·유죄인정 기록, 다수 보안업체 공개 분석 보고서)Gafgyt(Bashlite) 계열 (2014~). 셸 스크립트 하나가 CPU 종류별 정적 실행파일을 차례로 받아 실행하는 구조입니다. ’파우치 하나 + 케이블 여러 가닥’이 같은 경로에서 한 세션에 내려온 어제 모습과 생김새가 같습니다. (출처 유형: 다수 보안업체 공개 분석 보고서)
사실 여기서 멈춥니다. 검체 분류 서비스(VirusTotal)가 연동돼 있지 않습니다. 어제 파일에는 MalwareBazaar 태그도 없습니다. 그래서 어제 파일이 Mirai 계열이라는 판정은 하지 않습니다. 닮은 건 구조와 이름 붙이는 방식까지입니다.
그래서 뭘 해야 하나
파우치를 들고 오는 쪽은 우리가 막을 수 없습니다. 바꿀 수 있는 건 우리 기계에 꽂을 구멍이 열려 있느냐, 케이블을 받아 올 길이 열려 있느냐입니다.
사실
1. 기본 계정·쉬운 비밀번호를 그대로 쓰고 있다 · 가능성 높음
어제 기록된 주요 세션 다섯 건은 모두 로그인에 성공했습니다. 위 표의 admin/admin 은 13곳이 26번, 빈 비밀번호 root 는 6곳이 22번 넣어 봤습니다. 어제 관측된 진입 경로는 전부 자격증명이었습니다. 주제 세션은 로그인 후 19.30초 만에 실행파일 여섯 개를 손에 넣었습니다.
사실
2. 관리 포트, 특히 텔넷을 인터넷에 직접 열어 두고 있다 · 가능성 높음
텔넷은 세션의 32.4%인데, 파일을 받아 간 세션은 다섯 건 모두 텔넷이었습니다. SSH 쪽에서 파일을 놓고 간 접속 프로그램 표식은 16443846…(3곳) 하나뿐이었습니다. 집에 있는 공유기나 카메라 설정 화면에서 텔넷이 켜져 있는지 확인해 보세요.
추정 어제 내려온 ARM·MIPS 실행파일은 텔넷이 열린 공유기·CCTV 같은 장비를 겨냥한 구성입니다. 뚫리면 장비 하나가 통째로 넘어갑니다.
사실
3. 밖으로 나가는 연결을 막지 않고 있다 · 가능성 높음
어제 ‘파일 다운로드’ 의도가 39회, ’다운로드 후 실행’이 37회였습니다. 176[.]65[.]139[.]196/bins/ 에서 7건, 160[.]119[.]66[.]206/bins/ 에서 2건을 받아 갔습니다. 여섯 가닥 중 다섯이 정적 링크라 CPU 만 맞으면 어느 리눅스에서든 돌아갑니다. 서버가 밖으로 나가는 길이 막혀 있었다면 어떻게 됐을까요? 어제 세션은 케이블을 받아 오는 단계에서 끝났을 겁니다. 이게 이 글의 비유로 말하면 “가게에서 오는 물건을 받지 않는다”입니다. 일련번호가 몇 번 바뀌든 상관없습니다.
추정
4. 접속 빈도 제한(fail2ban 등)이 없다 · 가능성 중간
한 곳당 로그인 시도가 2.6회꼴입니다. admin/admin 은 곳당 2회입니다. “5번 틀리면 잠금” 같은 규칙에는 대부분 걸리지 않았을 겁니다. 적은 횟수로 넓게 두드리는 방식이라 빈도 제한만으로는 막기 어렵습니다. 기본 계정 없애기와 함께 써야 효과가 있습니다. 그래서 ’높음’을 붙이지 않았습니다.
사실 5. 비밀번호 로그인을 허용하고 열쇠 방식을 쓰지 않는다 · 가능성 낮음 어제 파일을 받아 간 세션은 모두 텔넷입니다. 텔넷에는 열쇠 방식이라는 선택지가 없습니다. SSH 로그인 시도가 몇 번이었는지는 따로 나뉘어 있지 않습니다. 그래서 열쇠 방식으로 어제 침입을 막을 수 있었다고 말할 근거가 없습니다. 텔넷은 끄는 것 말고는 답이 없습니다.
추정 6. 로그를 모으지 않거나 이상 행동 감시가 없다 · 가능성 중간 하루 전체에서 흔적 삭제 25회, 방어 무력화 1회가 있었습니다. 주제 세션에는 둘 다 없었습니다. 우리는 화면 녹화가 302건 있어서 19초짜리 세션의 흐름을 다시 맞출 수 있었습니다. 기록이 없었다면 한 달 전 가게가 다시 문을 열었다는 사실 자체를 몰랐을 겁니다.
사실
어제 관측한 유포지 176[.]65[.]139[.]196 과 160[.]119[.]66[.]206 은 C-TAS(한국인터넷진흥원의 사이버 위협정보 공유 체계) 신고 대상입니다. 다만 우리가 확인할 수 있는 건 전송이 성공했다는 것까지입니다. KISA 쪽에 실제로 올라갔는지는 따로 확인해야 합니다.
우리가 모르는 것
이 블로그가 다른 곳과 다른 지점입니다. 아는 것만큼 모르는 것도 적습니다.
파우치와 가게에 대해
- [확인 불가] 아카이브에 9/9 · 9/11 · 9/12 · 9/14 · 9/16 · 9/18 · 9/19 · 9/21 브리프가 없습니다. “
176[.]65[.]139[.]196이 32일 만에 나타났다”는 건 아카이브 29일치 기준입니다. 그 사이 이 가게가 쉬었는지는 모릅니다. - [확인 불가]
176[.]65[.]139[.]196(8/21 · 어제),.202(8/23~25),.206(9/17)이 같은 운영자인지 모릅니다. 확인되는 건 같은 /24 대역(앞 세 자리가 같은 주소 256개 묶음)이라는 것과,.196의 이름 규칙이 압축을 풀어 얻은 목록(31[.]77[.]227[.]121)과 겹친다는 것뿐입니다. 공개된 소스 계열이라 서로 관계없는 운영자도 같은 규칙을 씁니다. - [확인 불가]
px86·pmips는 8/21 과 주소·이름·종류가 같고 크기만 −160 / +320바이트 달라졌습니다. 같은 프로그램을 다시 만든 것인지, 다른 프로그램에 같은 이름을 붙인 것인지 검체 내용이 없어 판단할 수 없습니다. - [확인 불가]
parm5만 젠더가 필요한 동적 링크(uClibc)인 이유를 모릅니다. 실행하려면 대상 장비에/lib/ld-uClibc.so.0이 있어야 한다는 것까지만 파일 종류에서 읽힙니다. - [확인 불가] 여섯 가닥 중 어느 것이 실제로 실행됐는지(또는 실행을 시도했는지) 기록이 구분하지 않습니다. ‘다운로드 후 실행’ 의도는 있지만 명령 원문과 화면 녹화 내용이 없습니다.
- [확인 불가]
ATK-DD0862와 파일 8건을 잇는 근거는 배달자 칸과 개수 합(8 = 다운로드 수)이 맞는다는 것입니다. 세션과 파일을 1:1 로 잇는 칸은 없습니다. - [주의] 브리프는 “주소 기준 규칙이면 여덟 개를 모두 잡는다”고 적었습니다. 그런데 8건 중 9바이트 텍스트는 주소가 기록돼 있지 않습니다. 그래서 이 글은 “주소가 기록된 일곱 개”로 좁혀 적었습니다.
- [확인 불가] 9바이트 텍스트(
0dc95fb4…)가 9/17 · 9/20 · 어제 각각 다른 별칭에게서 나왔습니다. 내용이 없어서 무엇인지, 왜 같은 파일이 여러 출발지에서 나오는지 모릅니다.
다른 세션과 집계에 대해
- [확인 불가] 두 번째 서버 상위 출발지에
176.65.x.x(ATK-D4B7A8, 89건)가 있습니다. 가려진 주소라 유포지176[.]65[.]139[.]196과 같은 기계인지 알 수 없습니다. 복원하지 않습니다. 별칭이 두 서버 사이에서 같은 출발지를 가리킨다는 보장도 문서화돼 있지 않습니다. - [확인 불가]
ATK-DD41EC가 9/20 과 어제 같은 별칭으로 나왔습니다. 별칭을 만드는 방식이 문서화돼 있지 않아서, 날짜가 다른 두 기록을 같은 출발지로 묶는 근거로 쓰지 않았습니다. - [확인 불가]
ATK-040C4F는 ‘파일 다운로드’ 의도가 있는데 다운로드 수가 0 입니다. 받으려다 실패했는지, 받았는데 저장되지 않았는지 구분할 수 없습니다. - [확인 불가] 기록 촘촘함(completeness)의 계산식이 재료에 없습니다. 의도 1개인
ATK-DD41EC(42)가 의도 3개인ATK-DD0862(37)보다 높은 이유를 설명할 수 없습니다. - [확인 불가] 명령 790개와 의도 분류 합 491의 차이 299개가 무엇인지 재료가 설명하지 않습니다.
- [확인 불가] RDP 이름표
Administr·Admin이 9/20 대비 수십 배 늘어난 원인을 모릅니다. 출발지와 서비스를 잇는 칸이 없어서 한두 곳이 만든 숫자인지도 확인할 수 없습니다. - [확인 불가] 두 번째 서버의
adb상세 기록이 어제 재료에 없습니다. ADB(안드로이드 디버깅 연결) 130세션에 무엇이 들어왔는지, 몇 곳에서 왔는지 모릅니다. 두 번째 서버의 파일 4건(모두 8/28 · 8/30 · 9/3 · 9/20 에 이미 본 해시)이 ADB 로 들어왔는지도 확인할 수 없습니다. - [확인 불가] 접속 프로그램 표식 11개가 전체 47개 묶음 중 일부인지, 어제 본 전부인지 명시돼 있지 않습니다. 주제 세션은 텔넷이라 표식 자체가 없어서 묶음 분석을 적용하지 않았습니다. 표식은 프로그램의 표식이지 사람의 표식이 아닙니다.
일부러 빼거나 연결하지 않은 것
- [제외] 로그인 칸에 HTTP·SIP 요청이 잘못 들어온 것으로 보이는 3종은 비밀번호가 아니라 잡음으로 보고 인용 목록에서 뺐습니다. 그중 하나의 비밀번호 칸에 든 호스트 문자열은 적지 않습니다.
- [제외] 평문 지표로 남은 Discord 웹훅 1건은 어느 세션·파일과 연결되는지 재료에 없어서 사실 관계에서 뺐습니다.
- [제외] 배경 통계(KISA 보안공지 CVE 7,640건 · CISA KEV 404건 · 랜섬웨어 연계 확인 100건, EPSS 상위 CVE-2018-13379 · CVE-2022-26134 · CVE-2021-44228 · CVE-2023-4966 · CVE-2024-3400)는 어제 관측과 직접 연결되지 않습니다. 어제 침입 경로는 전부 자격증명이었습니다.
- [확인 불가] C-TAS 신고는 전송 성공까지만 확인됩니다. KISA 쪽 적재·활용 여부는 따로 확인해야 합니다.
아예 판단하지 않는 것
- 통신사·조직(ASN·ISP) — 관련 데이터베이스가 없습니다. 추정하지 않습니다. 유포지
176[.]65[.]139[.]196의 호스팅 업체도 모릅니다. - 지리 위치 — 같은 이유로 모릅니다. IP 지리정보는 애초에 누가 했는지를 가리는 근거가 되지 못합니다. 이 글은 어떤 국가·기업·개인도 공격자로 지목하지 않습니다.
- VPN·Tor·클라우드 여부 — 판별할 수단이 없습니다.
- 검체 분류(VirusTotal) — 연동돼 있지 않습니다. 어제 새 실행파일 여섯 개가 어떤 계열로 탐지되는지 이 글로는 말할 수 없습니다.
- 접속 프로그램 문자열(User-Agent) — 두 서버 모두 웹(HTTP)이 아닙니다. 첫 번째는 SSH·텔넷, 두 번째는 SMB·RDP·VNC·MSSQL·LDAP·ADB 입니다. 웹 공격은 별도 소스에서 다룹니다.
- 취약점 번호(CVE) 연결 — SSH·텔넷 공격은 대부분 특정 취약점을 참조하지 않습니다. 두 번째 서버도 규격을 맞추는 단계라 마찬가지입니다.
한 달 전에 본 파우치가 어제 다시 왔습니다. 주머니는 한 비트도 달라지지 않았습니다. 안에 든 케이블은 두 가닥에서 여섯 가닥으로 늘었고, 일련번호는 전부 새것이었습니다. 한 달 전 일련번호 목록으로는 여섯 가닥 중 하나도 잡지 못합니다. 대신 파우치가 오는 가게 주소는 그대로였습니다. 케이블에 붙은 이름표도 우리가 전에 상자를 뜯어서 봐 둔 그 이름이었습니다.
무엇이 바뀌었는지, 누가 가져왔는지는 모릅니다. 모르는 건 모른다고 둡니다. 그래도 할 수 있는 일은 분명합니다. 꽂을 구멍(텔넷)을 닫고, 케이블을 받아 올 길(바깥으로 나가는 연결)을 막고, 가게 주소를 오래 기억해 두는 것. 일련번호는 한 달이면 바뀌었습니다. 가게 주소는 32일이 지나도 그대로였습니다.
관측일은 2026년 9월 22일이고, 이 글은 다음 날 정리했습니다. 출발지 IP 는 브리프에 가림 처리된 형태(87.58.x.x, 222.86.x.x, 116.92.x.x, 160.119.x.x, 176.65.x.x) 그대로 옮겼고 복원하지 않았습니다. 유포지 주소는 실수로 접속되지 않도록 디팽(hxxp://, [.]) 상태를 본문과 IOC 블록 모두에서 유지했습니다. 자격증명은 서로 다른 IP 3곳 이상에서 반복 관측된 조합 13개만 원문 인용했고, 나머지 366개는 개수만 밝히고 값은 적지 않았습니다. 통신사·국적·VPN 여부처럼 우리에게 계측 수단이 없는 항목은 추정하지 않고 “모른다”로 남겨 뒀습니다.
