Accueil Solution du CTF No Exploiting Me : 1 de VulnHub
Post
Annuler

Solution du CTF No Exploiting Me : 1 de VulnHub

Présentation et mise en place

No Exploiting Me: 1 est un CTF créé par botnet_hunter, l’auteur de la série de challenges Bot Challenges téléchargeable sur VulnHub.

Ce CTF ne fait pas partie de cette série, l’objectif est ici de s’entraîner à l’identification et l’exploitation de vulnérabilités dans les bases NoSQL, les scripts PHP et les systèmes Unix.

Le challenge a été plutôt simple à résoudre en revanche il a été plus compliqué de faire fonctionner la VM :(

L’auteur n’a pas dû prendre en compte le fait que UDEV montre quelques réticences à monter une interface réseau pour une nouvelle adresse MAC or quand vous montez le VDI dans VirtualBox lors de la création d’une nouvelle VM vous changez forcément l’adresse MAC.

Pour mettre en place la VM j’ai dû récupérer l’adresse MAC d’origine dans un fichier UDEV depuis l’image disque.

Pour cela j’ai suivi une procédure qui consiste à charger le module noyau nbd, utiliser qemu-nbd pour avoir les différentes partitions dans /dev/ et finalement monter le disque avec mount.

Mais rassurez-vous : dans mon immense générosité, je vous donne ici l’adresse MAC d’origine pour que vous n’ayez plus qu’à la mettre correctement dans les préférences de la VM : 08:00:27:ae:1f:6e.

Laisse gros ! (Let’s go en lorrain)

En dehors des ports habituels on remarque un nouvel invité dans les services présents :

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
Starting Nmap 6.46 ( http://nmap.org ) at 2014-07-02 07:57 CEST
Nmap scan report for 192.168.1.56
Host is up (0.00019s latency).
Not shown: 65531 closed ports
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 5.5p1 Debian 6+squeeze3 (protocol 2.0)
| ssh-hostkey: 
|   1024 38:08:f7:c6:a2:57:94:c1:d8:8b:7e:a9:7f:84:42:8a (DSA)
|_  2048 07:90:a3:20:c6:b8:8a:cd:d0:05:06:4b:36:1b:9d:cc (RSA)
80/tcp    open  http    Apache httpd 2.2.16 ((Debian))
|_http-methods: No Allow or Public header in OPTIONS response (status code 200)
|_http-title: Login Page
27017/tcp open  mongodb MongoDB 2.4.6                                                                                                                                                                          
| mongodb-databases:                                                                                                                                                                                           
|   databases                                                                                                                                                                                                  
|     2                                                                                                                                                                                                        
|       empty = true                                                                                                                                                                                           
|       name = admin                                                                                                                                                                                           
|       sizeOnDisk = 1                                                                                                                                                                                         
|     0                                                                                                                                                                                                        
|       empty = false                                                                                                                                                                                          
|       name = NoExploitingMe                                                                                                                                                                                  
|       sizeOnDisk = 218103808                                                                                                                                                                                 
|     1                                                                                                                                                                                                        
|       empty = false                                                                                                                                                                                          
|       name = local                                                                                                                                                                                           
|       sizeOnDisk = 33554432                                                                                                                                                                                  
|   totalSize = 251658240                                                                                                                                                                                      
|_  ok = 1                                                                                                                                                                                                     
| mongodb-info:                                                                                                                                                                                                
|   MongoDB Build info                                                                                                                                                                                         
|     compilerFlags = -Wnon-virtual-dtor -Woverloaded-virtual ---snip--- -fno-builtin-memcmp -O3
|     version = 2.4.6
|     sysInfo = Linux bs-linux32.10gen.cc 2.6.21.7-2.fc8xen #1 SMP Fri Feb 15 12:39:36 EST 2008 i686 BOOST_LIB_VERSION=1_49
|     gitVersion = b9925db5eac369d77a3a5f5d98a145eaaacd9673
|     maxBsonObjectSize = 16777216
|     ok = 1
|     debug = false
|     bits = 32
|     loaderFlags = -fPIC -pthread -rdynamic
|     javascriptEngine = V8
|     versionArray
|       2 = 6
|       3 = 0
|       0 = 2
|       1 = 4
|     allocator = system
|   Server status
|     metrics
|       queryExecutor
|         scanned = 525
|       record
|         moves = 0
|       ttl
|         deletedDocuments = 0
|         passes = 247
|       operation
|         idhack = 0
|         fastmod = 0
|         scanAndOrder = 0
|       getLastError
|         wtime
|           totalMillis = 0
|           num = 0
|         wtimeouts = 0
|       document
|         updated = 0
|         returned = 31
|         inserted = 12
|         deleted = 11
|       repl
|         oplog
|           insertBytes = 0
|           insert
|             totalMillis = 0
|             num = 0
|         preload
|           docs
|             totalMillis = 0
|             num = 0
|           indexes
|             totalMillis = 0
|             num = 0
|         buffer
|           maxSizeBytes = 268435456
|           sizeBytes = 0
|           count = 0
|         apply
|           ops = 0
|           batches
|             totalMillis = 0
|             num = 0
|         network
|           getmores
|             totalMillis = 0
|             num = 0
|           readersCreated = 0
|           ops = 0
|           bytes = 0
|     uptimeEstimate = 14672
|     pid = 808
|     globalLock
|       lockTime = 51169
|       activeClients
|         writers = 0
|         readers = 0
|         total = 0
|       totalTime = 48976313000
|       currentQueue
|         writers = 0
|         readers = 0
|         total = 0
|     writeBacksQueued = false
|     ok = 1
|     recordStats
|       admin
|         accessesNotInMemory = 0
|         pageFaultExceptionsThrown = 0
|       local
|         accessesNotInMemory = 0
|         pageFaultExceptionsThrown = 0
|       pageFaultExceptionsThrown = 0
|       accessesNotInMemory = 0
|       NoExploitingMe
|         accessesNotInMemory = 0
|         pageFaultExceptionsThrown = 0
|     opcountersRepl
|       insert = 0
|       delete = 0
|       update = 0
|       command = 0
|       getmore = 0
|       query = 0
|     uptime = 48976
|     locks
|       .
|         timeLockedMicros
|           R = 203
|           W = 51169
|         timeAcquiringMicros
|           R = 22
|           W = 18
|       admin
|         timeLockedMicros
|           r = 39
|           w = 0
|         timeAcquiringMicros
|           r = 3
|           w = 0
|       NoExploitingMe
|         timeLockedMicros
|           r = 23849
|           w = 61211
|         timeAcquiringMicros
|           r = 682
|           w = 30839
|       local
|         timeLockedMicros
|           r = 17457
|           w = 0
|         timeAcquiringMicros
|           r = 1751
|           w = 0
|     localTime = 1404280716619
|     network
|       bytesIn = 3857
|       numRequests = 50
|       bytesOut = 8212
|     uptimeMillis = 48976313
|     version = 2.4.6
|     opcounters
|       insert = 12
|       delete = 2
|       update = 0
|       command = 32
|       getmore = 0
|       query = 502
|     mem
|       virtual = 360
|       resident = 32
|       supported = true
|       mapped = 240
|       bits = 32
|     host = NoExploitingMe
|     indexCounters
|       accesses = 22
|       resets = 0
|       hits = 22
|       misses = 0
|       missRatio = 0
|     backgroundFlushing
|       total_ms = 5
|       average_ms = 0.020242914979757
|       last_ms = 0
|       flushes = 247
|       last_finished = 1404280705165
|     extra_info
|       page_faults = 162
|       heap_usage_bytes = 23550376
|       note = fields vary by platform
|     cursors
|       timedOut = 0
|       totalOpen = 0
|       clientCursors_size = 0
|     process = mongod
|     connections
|       available = 817
|       current = 2
|       totalCreated = 55
|     asserts
|       rollovers = 0
|       regular = 0
|       user = 1
|       warning = 1
|_      msg = 0
28017/tcp open  http    MongoDB http console
|_http-methods: No Allow or Public header in OPTIONS response (status code 200)
|_http-title: mongod NoExploitingMe
MAC Address: 08:00:27:AE:1F:6E (Cadmus Computer Systems)
Device type: general purpose
Running: Linux 2.6.X
OS CPE: cpe:/o:linux:linux_kernel:2.6
OS details: Linux 2.6.32
Network Distance: 1 hop
Service Info: Host: NoExploitingMe; OS: Linux; CPE: cpe:/o:linux:linux_kernel

It’s not a bug, it’s a feature

MongoDB est un système de base de données NoSQL bien connu. Par contre il ne dispose pas d’un système d’authentification par conséquence si le service est exposé sur Internet tout le monde peut fouiller dans la base.

Le projet Un1c0rn recense différents serveurs vulnérables à un accès MongoDB ouvert.

Pour se connecter on se sert du client officiel MongoDB. Notez que pour certaines plateformes on trouve des binaires précompilés.

On passe en argument l’adresse IP du serveur ainsi que le nom de la base (récupérée plus tôt par Nmap, la vie est bien faite) :

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
$ ./mongo 192.168.5.56/NoExploitingMe
MongoDB shell version: 2.6.3
connecting to: 192.168.5.56/NoExploitingMe
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
	http://docs.mongodb.org/
Questions? Try the support group
	http://groups.google.com/group/mongodb-user
Server has startup warnings: 
Tue Jul  1 08:05:04.297 [initandlisten] 
Tue Jul  1 08:05:04.297 [initandlisten] ** NOTE: This is a 32 bit MongoDB binary.
Tue Jul  1 08:05:04.297 [initandlisten] **       32 bit builds are limited to less than 2GB of data (or less with --journal).
Tue Jul  1 08:05:04.297 [initandlisten] **       Note that journaling defaults to off for 32 bit and is currently off.
Tue Jul  1 08:05:04.297 [initandlisten] **       See http://dochub.mongodb.org/core/32bit
Tue Jul  1 08:05:04.297 [initandlisten] 
> help
	db.help()                    help on db methods
	db.mycoll.help()             help on collection methods
	sh.help()                    sharding helpers
	rs.help()                    replica set helpers
	help admin                   administrative help
	help connect                 connecting to a db help
	help keys                    key shortcuts
	help misc                    misc things to know
	help mr                      mapreduce

	show dbs                     show database names
	show collections             show collections in current database
	show users                   show users in current database
	show profile                 show most recent system.profile entries with time >= 1ms
	show logs                    show the accessible logger names
	show log [name]              prints out the last segment of log in memory, 'global' is default
	use <db_name>                set current database
	db.foo.find()                list objects in collection foo
	db.foo.find( { a : 1 } )     list objects in foo where a == 1
	it                           result of the last line evaluated; use to further iterate
	DBQuery.shellBatchSize = x   set default number of items to display on shell
	exit                         quit the mongo shell
> show collections
hashes
system.indexes
users
> db.hashes.find()
{ "_id" : ObjectId("53b2ce213d9f3b7ecb689e0c"), "hash" : "a9b7ba70783b617e9998dc4dd82eb3c5" }
{ "_id" : ObjectId("53b2ce213360db12c1cc98c4"), "hash" : "b8c37e33defde51cf91e1e03e51657da" }
{ "_id" : ObjectId("53b2ce21ab519d66c7e8c3fa"), "hash" : "fba9d88164f3e2d9109ee770223212a0" }
{ "_id" : ObjectId("53b2ce21a9b1a0d11763f3cb"), "hash" : "aa68c75c4a77c87f97fb686b2f068676" }
{ "_id" : ObjectId("53b2ce21e1f720407fee85d0"), "hash" : "fed33392d3a48aa149a87a38b875ba4a" }
{ "_id" : ObjectId("53b2ce21945ebf8f0a006cf6"), "hash" : "2387337ba1e0b0249ba90f55b2ba2521" }
{ "_id" : ObjectId("53b2ce219c83c438e69f11bd"), "hash" : "9246444d94f081e3549803b928260f56" }
{ "_id" : ObjectId("53b2ce21e840353b0712d206"), "hash" : "d7322ed717dedf1eb4e6e52a37ea7bcd" }
{ "_id" : ObjectId("53b2ce219dc693433f455c50"), "hash" : "1587965fb4d4b5afe8428a4a024feb0d" }
{ "_id" : ObjectId("53b2ce211092759e74e9c5a9"), "hash" : "31b3b31a1c2f8a370206f111127c0dbd" }
> db.users.find()
{ "_id" : ObjectId("53b2ce21bfbccdd3debcdcba"), "user" : "badadmin", "password" : "yes, this password does get reused" }

Dans la table hashes on trouve des hash MD5 vite cassés via les sites spécialisés : il s’agit des hashs des chiffres allant de 1009 à 1009.

Dans la table users on trouve un couple user/password qui nous permet de nous connecter sur le site web (port 80).

No feature !

Une fois connecté on se retrouve face à un formulaire qui permet de faire un lookup (on saisit un nom d’hôte et ça retourne l’adresse IP).

Comme on peut s’y attendre ce script est vulnérable à une faille d’injection de commande shell.

Faille d'injection de commande

Mais cette vulnérabilité n’a que peu d’intérêt, car comme le laisse supposer le mot de passe récupéré plus tôt on peut se connecter en tant que badadmin via ssh… et ça passe.

1
2
3
4
badadmin@NoExploitingMe:~$ id
uid=1000(badadmin) gid=1000(badadmin) groups=1000(badadmin),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)
badadmin@NoExploitingMe:~$ uname -a
Linux NoExploitingMe 2.6.32-5-686 #1 SMP Fri May 10 08:33:48 UTC 2013 i686 GNU/Linux

À la racine du système de fichier, on trouve un script genHashes.py dont le contenu est le suivant :

1
2
3
4
5
6
7
8
import hashlib
import os

for i in range(1000,1010):
	m = hashlib.md5()
	m.update(str(i))
	query = "db.hashes.save({'hash': '" + m.hexdigest() + "'})"
	os.system("mongo localhost:27017/NoExploitingMe --eval \"print(" + query + ")\"")

Ce script est appelé depuis rc.local :

1
2
3
4
5
6
mongo NoExploitingMe --eval "db.users.remove()" >> /dev/null
mongo NoExploitingMe --eval "db.users.save({'user':'badadmin','password':'yes, this password does get reused'})" >> /dev/null

mongo NoExploitingMe --eval "db.hashes.remove()" >> /dev/null
python /genHashes.py >> /dev/null
exit 0

Administrateur Labavure

Maintenant on cherche comment passer root et après recherche je n’ai trouvé que cette backup de /etc/shadow trop accessible dans /etc :

1
-rw------- 1 badadmin root     783 Sep  1  2013 shadow.backup

Contenu :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
root:$6$76E0ztyw$sgBZAekia9WO8k3bM2/xpPVkISpvmB7SDIzjmZHi0uN8wHfdUSfpgQ1AZpdtA6rRGZN7SYcHQujSHF3xwog030:15950:0:99999:7:::
daemon:*:15949:0:99999:7:::
bin:*:15949:0:99999:7:::
sys:*:15949:0:99999:7:::
sync:*:15949:0:99999:7:::
games:*:15949:0:99999:7:::
man:*:15949:0:99999:7:::
lp:*:15949:0:99999:7:::
mail:*:15949:0:99999:7:::
news:*:15949:0:99999:7:::
uucp:*:15949:0:99999:7:::
proxy:*:15949:0:99999:7:::
www-data:*:15949:0:99999:7:::
backup:*:15949:0:99999:7:::
list:*:15949:0:99999:7:::
irc:*:15949:0:99999:7:::
gnats:*:15949:0:99999:7:::
nobody:*:15949:0:99999:7:::
libuuid:!:15949:0:99999:7:::
badadmin:$6$ShlSo9yK$iV8rDXanfKij2AlFTDHlk7O6thRUZsTSFHL7aHclHRgzOeuJoVtMeu3jAqzodilguinqnL6rFC2h7Q5ihU9.p/:15950:0:99999:7:::
mongodb:*:15949:0:99999:7:::
sshd:*:15950:0:99999:7:::

Les hashs étant en sha512 c’est difficile de casser le mot de passe root. A raison de 400 tentatives la seconde on en a pour un moment.

Le mot de passe n’étant pas tombé avec la wordlist de RockYou j’ai préféré laisser tomber.

Published July 02 2014 at 18:41

Cet article est sous licence CC BY 4.0 par l'auteur.