Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JetBrains TeamCity HTTP Login Scanner #19601

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

sjanusz-r7
Copy link
Contributor

@sjanusz-r7 sjanusz-r7 commented Oct 30, 2024

This PR adds in a new login scanner module that targets the JetBrains TeamCity service.

Docker

You can easily set up a TeamCity instance using Docker:
Latest:

docker run -it --rm -p 8111:8111 jetbrains/teamcity-server

10.0:

docker run -it --rm -p 8222:8111 jetbrains/teamcity-server:10.0

9.1.7:

docker run -it --rm -p 8333:8111 jetbrains/teamcity-server:9.1.7

Conveniently, the oldest available image in Docker and the newest images share the same encryption scheme and both work out of the box with no additional configuration or checking of the server version needed.

Verification

  • Boot up a Docker instance of JetBrains TeamCity and perform the initial setup in your browser
  • Start msfconsole
  • use scanner/teamcity/teamcity_login
  • run rport=8111 rhost=127.0.0.1 username=... password=...
  • Verify that you can log in
  • Verify that when using a password file, your user gets locked out but after waiting, you can login as expected

Example

 bundle exec 'ruby ./msfconsole -q'
msf6 auxiliary(scanner/teamcity/teamcity_login) > run

[+] 127.0.0.1:8111 - Login Successful: admin:admin
[!] No active DB -- Credential data will not be saved!
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

msf6 auxiliary(scanner/teamcity/teamcity_login) > run pass_file=pass_list.txt password=''

[-] 127.0.0.1:8111 - LOGIN FAILED: admin:admin_password (Incorrect)
[!] No active DB -- Credential data will not be saved!
[-] 127.0.0.1:8111 - LOGIN FAILED: admin:password (Incorrect)
[-] 127.0.0.1:8111 - LOGIN FAILED: admin:my_password111 (Incorrect)
[-] 127.0.0.1:8111 - LOGIN FAILED: admin:f00bar123! (Incorrect)
[-] 127.0.0.1:8111 - LOGIN FAILED: admin:p4$$w0rd01!! (Incorrect)
[*] User 'admin' locked out for 59 seconds. Sleeping, and retrying...
[-] 127.0.0.1:8111 - LOGIN FAILED: admin:admin_admin (Incorrect)
[-] 127.0.0.1:8111 - LOGIN FAILED: admin:adminadmin (Incorrect)
[+] 127.0.0.1:8111 - Login Successful: admin:admin
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

msf6 auxiliary(scanner/teamcity/teamcity_login) > cat pass_list.txt
[*] exec: cat pass_list.txt

admin_password
password
my_password111
f00bar123!
p4$$w0rd01!!
admin_admin
adminadmin
admin

Non-English Support

msf6 auxiliary(scanner/teamcity/teamcity_login) > run username='' password='' user_file=japanese.txt pass_file=japanese.txt

[+] 127.0.0.1:8111 - Login Successful: メタスプライトが大好きです:メタスプライトが大好きです
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

msf6 auxiliary(scanner/teamcity/teamcity_login) > run username='' password='' user_file=french.txt pass_file=french.txt

[+] 127.0.0.1:8111 - Login Successful: çççççç:çççççç
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

class Teamcity < HTTP
DEFAULT_PORT = 8111
LIKELY_PORTS = [8111]
LIKELY_SERVICE_NAMES = ['skynetflow'] # Comes from nmap 7.95 on MacOS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib/rex/proto/teamcity/rsa.rb Outdated Show resolved Hide resolved
lib/metasploit/framework/login_scanner/teamcity.rb Outdated Show resolved Hide resolved
lib/metasploit/framework/login_scanner/teamcity.rb Outdated Show resolved Hide resolved
lib/metasploit/framework/login_scanner/teamcity.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/http/teamcity.rb Outdated Show resolved Hide resolved
return { status: UNABLE_TO_CONNECT, proof: res } if res.body.match?('ajax') # TODO: Get the exact error message here.
return { status: INVALID_PUBLIC_PART, proof: res } if res.body.match?('publicKeyExpired') # TODO: Invalid public part? Or Incorrect/Unable_to_connect?

{ status: :success, proof: res }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth adding some positive assertions here to verify we're logged in, versus defaulting to success?

I guess it might be better to have false positives so that users report bugs for us to fix, versus false negatives that cause users to miss valid creds though 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants