Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! /bin/sh
- #
- # decode_passwords for FRITZ!OS versions > 06.05
- #
- # Copyright (C) 2014 P.Haemmerlein (http://www.yourfritz.de)
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License under
- # http://www.gnu.org/licenses/gpl-2.0.html
- # for more details.
- #
- # There's a small license deviance, if you want to incorporate the script into your
- # own software, please read the description below to take note of that.
- #
- # "FRITZ!Box" and "FRITZ!" are registered word marks and "AVM" is a registered
- # word and figurative mark of:
- # AVM Computersysteme Vertriebs GmbH, 10559, Berlin, DE.
- #
- # A registered entry for "FRITZ!OS" could not be found as of that date (09-05-2014),
- # but perhaps the legal protection of "FRITZ!" is expanded to the term "FRITZ!OS" too.
- #
- #######################################################################################
- #
- # Purpose:
- # --------
- # - decode encrypted credentials from a configuration file
- # - sustitute the former -c switch for {all,usb,wlan}cfgconv utilities
- #
- # Usage:
- # ------
- #
- # decode_passwords < {input_data}
- #
- # The script is designed as a filter using standard input and standard output. If you
- # use it as standard input for a command interpreter via a pipe, you can use file
- # descriptor 3 to provide the data stream to process instead of stdin.
- #
- # The input data may be any text. Any data looking like an encrypted item as it is
- # used by AVMs reversible encryption (that is a string starting with four dollar signs
- # followed only by the characters A to Z and 1 to 6) will be extracted and the script
- # will try as hard as possible to decrypt it.
- #
- # The simplest input contains only one such secret value, but you may let point stdin
- # of the script to a whole file like /var/flash/ar7.cfg too.
- #
- # If it's impossible to decode an encrypted value, it will remain unchanged.
- #
- # The converted input (substitution between encrypted and decrypted data is done
- # using the 'sed' command) will be written to stdout.
- #
- # To prevent unexpected behaviour (waiting for input because of an omitted redirection)
- # the script will refuse to work, if its standard input is attached to a terminal
- # device. If it's your intention to use it such way, specify 'tty' as 1st argument.
- #
- # Exit codes:
- # -----------
- # 0 - input data (if any) processed
- # 121 - unable to create a private temporary directory
- # 122 - the stdin file points to a terminal device and the 'tty' argument is absent
- # 123 - the specified WLAN key for mimicry seems to be unusual
- # 124 - the specified MAC address for mimicry seems to be invalid
- # 125 - the temporary path looks suspicious
- # 126 - missing 'webdavcfginfo' binary
- # 127 - invalid arguments specified, usage help will be shown
- #
- # Lean and mean version:
- # ----------------------
- # There's a tradeoff between a well-documented script with embedded comments and the
- # requirement for some purposes (a.e. the ruKernelTool utility) to write the script
- # to a device using a telnet shell session, execute it one or more times and forget
- # it afterwards.
- #
- # To produce such a lean version, you can call the script with the argument
- # 'leanandmean' as first parameter and it will write a version of itself without error
- # messages or any comments and line indentations to stdout. The pure content will be
- # put into a short wrapper script like this:
- #
- # cat >/var/decode_passwords <<-"LEANANDMEAN"
- # >> script code is placed here <<
- # LEANANDMEAN
- # chmod 550 /var/decode_passwords
- # [ $(md5sum </var/decode_passwords | sed -n -e 's/^\([0-9a-f]*\).*/\1/p') \
- # (cont) == 39f69aa3fb14198462c45fe56f7ed4cc ] || \
- # (cont) echo "Hash difference found, transmission failed." 1>&2
- #
- # You can customize the above "wrapper" script with some more arguments. The target
- # file name at the device may be specified as second parameter, default value is
- # '/var/decode_passwords' which will write the script to volatile storage at tmpfs.
- # If you'd prefer to do without the final hash check, you can specify *any* item as
- # third argument. If its length is greater than zero, no MD5 check will take place
- # at the wrapper.
- #
- # And finally you can specify another word (the fourth argument) with 2any content
- # and its pure presence will remove some additional code (look below for 'mimicry'
- # explanations) from the lean script version.
- #
- # At the time of this writing the lean version (without mimicry) uses 90 lines
- # with 2046 characters (bytes) at the target system and 4 additional lines (+258
- # bytes) for the default wrapper.
- #
- # If you compare these values with the "full blown" version (~520 lines and ~19,600
- # bytes), there's a significant difference. And as long as nobody will really read
- # the lean version to understand what it's doing, there's no need to transfer so
- # much useless data to the box.
- #
- # For that (and only that) purpose you may use the special lean version without any
- # copyright notice and without the included license reference(s).
- # If you want to incorporate the lean version of this script into your own software,
- # you are obligated to bundle the full version with your software too, without any
- # additional need for the casual user to send a special request for it.
- #
- # In this case you may bundle the script with your own software without the need
- # to publish your own source code too, if it's not required by other licenses.
- #
- # Mimicry of another box:
- # -----------------------
- # If you've got the *internal* presentation of any configuration file from another
- # box (which is out of reach yet - for example due to a hardware failure as the
- # result of overvoltage) together with the WLAN key printed on the back of that
- # device *and* its MAC address (could be found at the "urlader environment" or may
- # be extracted from another computer, which had network access to the device
- # earlier - but it is send as "serial number" to AVMs DynDNS service and with
- # every TR-069 INFORM request too), you can try to decrypt the secret data from
- # that file, if you specify the two values mentioned above as parameters:
- #
- # decode_passwords wlan_key mac_address < input_file
- #
- # Currently this has been tested to be interoperable between the following
- # FRITZ!Box models:
- # 7270v1, 7270v2, 7270v3, 7390, 7490
- #
- # It does *not work* with a 6360 router, probably the IV for the AES encryption
- # will use some additional "device specific" data there.
- #
- # The 'mimicry' will *not work* with an exported configuration file. There is a
- # realistic possibility to import such a file, if you can fool the configuration
- # importer (/usr/www/cgi-bin/firmwarecfg or /usr/bin/tr069fwupdate) with a chroot
- # environment, but that's another story ...
- #
- # To check the ability of your device to mimicry another one, I've encoded a known
- # cleartext (username = "ippf@myfritz.net" and password = "1234567890") with a
- # 'faked' WLAN key (1234567890123456) and even a different MAC address value of
- # '11:22:33:44:55:66'. You can find the sample as (unreachable) shell code around
- # line 330.
- #
- # Prerequisites:
- # --------------
- # The whole script needs only a busybox with the following commands supported:
- # cat, sed, grep, mount/umount, cp, mkdir, date, echo, chroot, expr,
- # test (called as [)
- #
- # It's a matter of course that the 'webdavcfginfo' binary from the original firmware
- # has to be reachable (and that includes 'executable') too.
- #
- # If you create the lean and mean version, there are some more depedencies:
- # md5sum, chmod
- #
- # Just for fun:
- # The (imho) leanest version - with some additional limitations, but using the same
- # control flow - *could* be:
- #
- # b=/bin
- # l=/lib
- # f=/var/flash
- # t=/var/$$
- # m=mount
- # r=proc
- # mkdir -p $t$f $t$l $t$b $t/$r
- # cd $t
- # cat $*>i
- # sed -ne's/.*\(\$\$\$\$[A-Z1-6]*\).*/\1/p'<i>p
- # cat>s<<'Q'
- # q=\\\\
- # while read x;do
- # echo -e "$1$2 {$5=$x;}">$4
- # o="$($1$3 -p$5)"
- # o="${o//$q/$q$q}"
- # o="${o//|/\\|}"
- # o="${o//&/\\&}"
- # o="${o//\"/$q\"}"
- # echo "s|$x|$o|">>c
- # done<p
- # Q
- # $m -o bind $l .$l
- # $m -o bind $b .$b
- # $m -t $r . ./$r
- # chroot . sh s webdav client cfginfo $f/usb.cfg username
- # sed -fc<i
- # cd ..
- # u$m $t/$r $t$b $t$l
- # rm -r $t
- #
- # That version needs only 469 bytes on 30 lines and could do the basic job too. And
- # another benefit: You can specify one or more names of files to decode as arguments,
- # for example: 'sh micro_decode /var/flash/*.cfg'.
- # It's only a proof of concept and not intended for distribution from other sources.
- # Please respect that license limitation.
- #
- #######################################################################################
- #
- # the "abused" AVM binary
- #
- decode=/bin/webdavcfginfo
- if [ ! -x $decode ]; then
- # LAM-EXCLUDE 1
- echo "Missing $decode executable ..." 1>&2
- exit 126
- fi
- #
- # the config file name for the decoder above and the needed entries within
- #
- cfg=/var/flash/usb.cfg
- client=webdavclient
- username=username
- #
- # some file names pooled here for easy changes in case of conflicts
- #
- in=input
- enc=passwords
- sc=sedcmds
- ms=script
- ue=urenv
- shl=/bin/sh
- pm=/proc/mounts
- tddef=/var/tmp
- # LAM-EXCLUDE 1
- leanname=/var/decode_passwords
- #
- # here we'll store our temporary files ...
- #
- tmpdir=$([ -z $TMP ] && echo $tddef || echo $TMP)/dpwd-$$-$(date +%s)
- if [ ${#tmpdir} -lt 20 ]; then
- # LAM-EXCLUDE 1
- echo -e "The path to my temporary directory ($tmpdir) seems to be too short.\nAt least 20 characters are expected." 1>&2
- exit 125
- fi
- #
- # if we can write there
- #
- mkdir -p $tmpdir || exit 121
- #
- # to ease things in case of an error, we'll put together the needed commands for a clean exit and execute them using a trap
- #
- cleanup()
- {
- #
- # ensure a valid directory name first (shortest possible value is regexp('/./dpwd-[0-9]?-[0-9]{10,}') = 20)
- #
- [ ${#tmpdir} -lt 20 ] && return
- # LAM-EXCLUDE-MIMICRY-BEGIN
- #
- # unmount urlader environment first, if it was overlayed within our procfs
- #
- grep "${tmpdir}.*${urenv}" $pm | while read t mp m; do umount $mp; done
- # LAM-EXCLUDE-MIMICRY-END
- #
- # unmount everything linked under our temporary directory
- #
- grep $tmpdir/proc $pm | while read t mp m; do umount $mp; done
- grep $tmpdir/bin $pm | while read t mp m; do umount $mp; done
- grep $tmpdir/lib $pm | while read t mp m; do umount $mp; done
- grep $tmpdir $pm | while read t mp m; do umount $mp; done
- #
- # remove our temp files
- #
- [ -d $tmpdir ] && rm -r $tmpdir >/dev/null 2>&1
- }
- #
- # the next section is only necessary for "double use" to create the smaller version from the "well-documented" one
- #
- # LAM-EXCLUDE-BEGIN
- if [ x$1 == xleanandmean ]; then
- # reproduce a (temporary) lean and mean version of myself for easy transfer to a box within a shell session
- # - to exclude only a few lines from the output, add a line "# LAM-EXCLUDE n" before them where n is the number of following lines to ignore
- # - to exclude a continuous section, place "# LAM-EXCLUDE-BEGIN" and "# LAM-EXCLUDE-END" around it
- # the second parameter could be the name at the target system
- [ ${#2} -gt 0 ] && target=$2 || target=$leanname
- # the third argument (if any) is used to exclude the final hash check
- [ ${#3} -gt 0 ] && nomd5=1 || nomd5=0
- # exclude support for "foreign" encoded values from small version
- [ ${#4} -gt 0 ] && nomimicry=1 || nomimicry=0
- # build the small versions
- leanandmean()
- {
- out() { echo "$1" 1>&3 ; echo "$1" >>$tmpout; }
- local tmpout=$tmpdir/out$(date +%s)
- local tmpin=$tmpdir/in$(date +%s)
- local tmpcmd=$tmpdir/cmd$(date +%s)
- local mode=$1 nomim=$2 lineno lines
- out "#! $shl"
- cat $0 >$tmpin
- # remove all mimicry code first
- [ $nomim -eq 1 ] && sed -e '/^[ \t]*# LAM-EXCLUDE-MIMICRY-BEGIN/,/^[ \t]*# LAM-EXCLUDE-MIMICRY-END/d' -i $tmpin
- # remove all complete LAM-EXCLUDE sections
- sed -e '/^[ \t]*# LAM-EXCLUDE-BEGIN/,/^[ \t]*# LAM-EXCLUDE-END/d' -i $tmpin
- # now we will look for '# LAM-EXCLUDE n' comments
- touch $tmpcmd
- for lineno in $(sed -n -e '/^[ \t]*# LAM-EXCLUDE [0-9]*$/=' $tmpin); do
- lines=$(sed -n -e "${lineno}s/^.* \([0-9]*\).*$/\1/p" $tmpin)
- echo "${lineno},$(( lineno + lines ))d" >>$tmpcmd
- done
- [ -s $tmpcmd ] && sed -f $tmpcmd -i $tmpin
- sed -e '/^[ \t]*#.*/d' -e 's/^[ \t]*\(.*\)$/\1/' -i $tmpin
- cat $tmpin >>$tmpout
- cat $tmpin 1>&3
- echo $(md5sum $tmpout | sed -n -e 's/^\([0-9a-f]*\).*/\1/p')
- }
- # output the wrapper
- echo "cat >$target <<-\"LEANANDMEAN\""
- MD5=$(leanandmean ${1:0:1} $nomimicry) 3>&1
- echo "LEANANDMEAN"
- echo "chmod 550 $target"
- [ $nomd5 -eq 0 ] && echo "[ \$(md5sum <$target | sed -n -e 's/^\([0-9a-f]*\).*/\1/p') == $MD5 ] || echo \"Hash difference found, transmission failed.\" 1>&2"
- cleanup
- exit 0
- #
- # the unreachable code here can be used to check the 'mimicry' ability, copy the lines to a separate file, change them as needed and try it yourself
- #
- #! /bin/sh
- urenv=/proc/sys/urlader/environment
- key="wlan_key"
- mac="maca"
- decode="decode_passwords"
- encoded="username = \"\$\$\$\$GDAC24NUP3BNNQZ2SUWNFP2FH5ZLOA6ORXMYP1UOUEZE2UI3SYXXVVS15SRGNUW1C2I4V2FZLARCYKXO\";\npassword = \"\$\$\$\$WDLEUNJT1IJWZSQBBQMGXXXHTX2FV3ZQYMYCZPJEREFYXQ4CAYIWSXIXRVITC4HSA6AY65IRK5SSOKXO\";"
- original_key="$(sed -n -e "/^$key/s/^[^\t]*\t\(.*\)/\1/p" <$urenv)"
- original_mac="$(sed -n -e "/^$mac/s/^[^\t]*\t\(.*\)/\1/p" <$urenv)"
- delim="======================================================"
- echo $delim
- echo "original wlan key is '$original_key'"
- echo "original maca is '$original_mac'"
- echo "decode with original wlan key and maca ..."
- echo -e "$encoded" | $decode
- echo $delim
- echo "replace wlan key with '1234567890123456'"
- echo "replace maca with '11:22:33:44:55:66'"
- echo "decode now with replaced values ..."
- echo -e $encoded | $decode 1234567890123456 11:22:33:44:55:66
- echo $delim
- if echo -e $encoded | $decode 1234567890123456 11:22:33:44:55:66 | grep -q "ippf@myfritz.net"; then
- echo "Decoding with foreign $key and $mac is possible."
- else
- echo "Decoding with foreign $key and $mac is NOT POSSIBLE."
- fi
- #
- # end of embedded mimicry sample
- #
- fi
- # LAM-EXCLUDE-END
- # LAM-EXCLUDE-MIMICRY-BEGIN
- #
- # the "box specific" variables for the AES IV
- #
- key_name="wlan_key"
- mac_name="maca"
- #
- # and where to find them
- #
- urenv="/proc/sys/urlader/environment"
- #
- # check arguments - we do not expect any, if not "mimicry" is intended too or tty detection is set to off
- #
- igntty=0
- if [ ${#1} -gt 0 ]; then
- if [ ${#2} -eq 0 ]; then
- # LAM-EXCLUDE 4
- if [ x$1 != xtty ]; then
- echo "Usage: $0 {${key_name}} {${mac_name}} <{config_file}" 1>&2
- echo "- decode {config_file} from a foreign box which had the specified {${key_name}} and {${mac_name}} address" 1>&2
- echo "- if called without {${key_name}} and {${mac_name}}, decode with settings from the box where the script is running" 1>&2
- exit 127
- # LAM-EXCLUDE 3
- else
- igntty=1
- fi
- else
- key="$1"
- mac="$2"
- if [ ${#key} -ne 16 -a ${#key} -ne 20 ] || [ -n "$(echo -n ${key} | sed -e 's/[0-9]//g')" ]; then
- # LAM-EXCLUDE 1
- echo "The specified ${key_name} is unusual, it should be composed of 16 or 20 decimal digits." 1>&2
- exit 123
- fi
- if [ -n "$(echo -n ${mac} | sed -e 's/^\([0-9A-F]\{2\}:\)\{5\}[0-9A-F]\{2\}$//')" ]; then
- # LAM-EXCLUDE 1
- echo "The specified ${mac_name} address is invalid, only hexadecimal digits (with A to F in uppercase) and double colons are permitted (hh:hh:hh:hh:hh:hh)." 1>&2
- exit 124
- fi
- fi
- fi
- # LAM-EXCLUDE-MIMICRY-END
- # get list of files to incorporate into the chroot environment
- chroot_files() { cat <<-EOT
- # list of files/actions for chroot jail preparation
- #
- # type params action
- # D <dir> create directory <dir>
- # E <dst> create empty file (with "echo -n" for correct character device handling at TFFS) <dst>
- # M <type> <src> <dst> mount file system of type <type> from <src> at <dst>
- # B <src> <dst> bind mount from <src> to <dst>
- D var/flash
- E $cfg
- M proc none proc
- B bin $1/bin
- B lib $1/lib
- EOT
- }
- #
- # prepare the chroot environment for the decoder utility
- #
- prepare_chroot()
- {
- rel_path() { [ -z $1 ] && return 1; [ ${1:0:1} == / ] && echo ${1:1} || echo $1; }
- dir_path() { [ -z $1 ] && return 1; [ ${1%/*} == $1 ] && echo -n || echo ${1%/*}; }
- c=$1
- while read line; do
- set -- $line
- case $1 in
- D)
- p=$c/$(rel_path $2); mkdir -p $p
- ;;
- E)
- d=$c/$(rel_path $2); mkdir -p $(dir_path $d); echo -n >$d
- ;;
- M)
- t=$2; s=$3; d=$c/$(rel_path $4); mkdir -p $d; mount -t $t $s $d
- ;;
- B)
- s=/$(rel_path $2); d=/$(rel_path $3); mkdir -p $d; mount -o bind $s $d
- ;;
- *)
- ;;
- esac
- done
- }
- #
- # setup a trap for possible condition, not all will work as expected
- #
- trap 'cleanup' EXIT HUP
- #
- # We expect our input via stdin and save it for repeated use to a temporary file.
- #
- if [ -t 0 -a $igntty -eq 0 ]; then
- # LAM-EXCLUDE 1
- echo -e "It looks like you've missed redirecting any input data to that script.\nFor intentional reading of stdin from a terminal, specify 'tty' as first argument." 1>&2
- exit 122
- fi
- [ -L /proc/self/fd/3 ] && fd=3 || fd=0
- cat /proc/self/fd/$fd >$tmpdir/$in
- #
- # an empty input file isn't an error, but we can avoid all that stress
- #
- [ ! -s $tmpdir/$in ] && exit 0
- #
- # extract all encrypted data from input and put each item on a single line in 'passwords'
- #
- sed -n -e 's/.*\(\$\$\$\$[A-Z1-6]*\).*/\1/p' <$tmpdir/$in >$tmpdir/$enc
- #
- # We'll use sed to write the converted file to stdout later, so we have to make sure,
- # there's a command file (even if it's empty) for the final sed call.
- #
- touch $tmpdir/$sc
- #
- # prepare the chroot environment now, if there's something to decode
- #
- if [ x$(sed -e "/^[ \t]*$/d" $tmpdir/$enc | sed -n -e '$=') != x ]; then
- chroot_files $tmpdir | prepare_chroot $tmpdir
- #
- # that's the part which will be called within the chroot environment, we'll write it to a file there
- # some substitutions will take place here, remember to escape runtime variable references
- #
- cat >$tmpdir/$ms <<-ENDOFWORKER
- while read in; do
- # prepare config file
- echo -n -e "$client {\n\t$username = \"\$in\";\n}" >$cfg
- # let it decode
- out="\$($decode -p username)"
- # if the decoded text is empty, no escaping is needed
- if [ \${#out} -gt 0 ]; then
- # backslash is escape, we've to double each occurence
- out="\${out//\\\\\\\\/\\\\\\\\\\\\\\\\}"
- # ampersand means matched expression but we want the pure character
- out="\${out//&/\\\\&}"
- # pipe symbol is our delimiter, escape it too
- out="\${out//|/\\\\|}"
- # and last but not least the original AVM implementation had escaped
- # any embedded double quotes, so we'll do that too
- out="\${out//\"/\\\\\\\\\"}"
- fi
- # output the s-command for later execution
- echo "s|\${in}|\${out}|g" >>/$sc
- done </$enc
- ENDOFWORKER
- # LAM-EXCLUDE 2
- # not really needed, but let's remove comments from worker, if it's not the lean version, you may want to comment out that step
- sed -e '/^[ \t]*#.*/d' -i $tmpdir/$ms
- # LAM-EXCLUDE-MIMICRY-BEGIN
- if [ ${#key} -gt 0 -a ${#mac} -gt 0 ]; then
- sed -e "/^${key_name}/s/^\([^\t]*\t\).*/\1${key}/" -e "/^${mac_name}/s/^\([^\t]*\t\).*/\1${mac}/" <$tmpdir$urenv >$tmpdir/$ue
- mount -o bind $tmpdir/$ue $tmpdir$urenv
- fi
- # LAM-EXCLUDE-MIMICRY-END
- #
- # call ourself within the jail
- #
- chroot $tmpdir $shl /$ms
- fi
- #
- # let sed change the input and do the output to stdout with one step
- #
- sed -f $tmpdir/$sc <$tmpdir/$in
- #
- # remember that 'cleanup' will take place here via a trap condition
- #
- exit 0
Add Comment
Please, Sign In to add comment