mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-22 02:53:28 +00:00
256 lines
22 KiB
Markdown
256 lines
22 KiB
Markdown
# OAuth para Tomada de Conta
|
|
|
|
{% hint style="success" %}
|
|
Aprenda e pratique Hacking AWS:<img src="../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../.gitbook/assets/arte.png" alt="" data-size="line">\
|
|
Aprenda e pratique Hacking GCP: <img src="../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
|
|
|
<details>
|
|
|
|
<summary>Support HackTricks</summary>
|
|
|
|
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
|
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
|
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|
|
{% endhint %}
|
|
|
|
<figure><img src="https://pentest.eu/RENDER_WebSec_10fps_21sec_9MB_29042024.gif" alt=""><figcaption></figcaption></figure>
|
|
|
|
{% embed url="https://websec.nl/" %}
|
|
|
|
## Informações Básicas <a href="#d4a8" id="d4a8"></a>
|
|
|
|
OAuth oferece várias versões, com insights fundamentais acessíveis na [documentação do OAuth 2.0](https://oauth.net/2/). Esta discussão centra-se principalmente no amplamente utilizado [tipo de concessão de código de autorização do OAuth 2.0](https://oauth.net/2/grant-types/authorization-code/), fornecendo um **quadro de autorização que permite que um aplicativo acesse ou execute ações na conta de um usuário em outro aplicativo** (o servidor de autorização).
|
|
|
|
Considere um site hipotético _**https://example.com**_, projetado para **exibir todas as suas postagens em redes sociais**, incluindo as privadas. Para alcançar isso, o OAuth 2.0 é empregado. _https://example.com_ solicitará sua permissão para **acessar suas postagens em redes sociais**. Consequentemente, uma tela de consentimento aparecerá em _https://socialmedia.com_, delineando as **permissões solicitadas e o desenvolvedor que faz a solicitação**. Após sua autorização, _https://example.com_ ganha a capacidade de **acessar suas postagens em seu nome**.
|
|
|
|
É essencial compreender os seguintes componentes dentro do quadro do OAuth 2.0:
|
|
|
|
* **proprietário do recurso**: Você, como o **usuário/entidade**, autoriza o acesso ao seu recurso, como suas postagens em redes sociais.
|
|
* **servidor de recursos**: O **servidor que gerencia solicitações autenticadas** após o aplicativo ter obtido um `access token` em nome do `proprietário do recurso`, por exemplo, **https://socialmedia.com**.
|
|
* **aplicativo cliente**: O **aplicativo que busca autorização** do `proprietário do recurso`, como **https://example.com**.
|
|
* **servidor de autorização**: O **servidor que emite `access tokens`** para o `aplicativo cliente` após a autenticação bem-sucedida do `proprietário do recurso` e a obtenção de autorização, por exemplo, **https://socialmedia.com**.
|
|
* **client\_id**: Um identificador público e único para o aplicativo.
|
|
* **client\_secret:** Uma chave confidencial, conhecida apenas pelo aplicativo e pelo servidor de autorização, usada para gerar `access_tokens`.
|
|
* **response\_type**: Um valor que especifica **o tipo de token solicitado**, como `code`.
|
|
* **scope**: O **nível de acesso** que o `aplicativo cliente` está solicitando do `proprietário do recurso`.
|
|
* **redirect\_uri**: A **URL para a qual o usuário é redirecionado após a autorização**. Isso geralmente deve estar alinhado com a URL de redirecionamento pré-registrada.
|
|
* **state**: Um parâmetro para **manter dados durante a redireção do usuário para e do servidor de autorização**. Sua singularidade é crítica para servir como um **mecanismo de proteção CSRF**.
|
|
* **grant\_type**: Um parâmetro que indica **o tipo de concessão e o tipo de token a ser retornado**.
|
|
* **code**: O código de autorização do `servidor de autorização`, usado em conjunto com `client_id` e `client_secret` pelo aplicativo cliente para adquirir um `access_token`.
|
|
* **access\_token**: O **token que o aplicativo cliente usa para solicitações de API** em nome do `proprietário do recurso`.
|
|
* **refresh\_token**: Permite que o aplicativo **obtenha um novo `access_token` sem solicitar novamente ao usuário**.
|
|
|
|
### Fluxo
|
|
|
|
O **fluxo real do OAuth** prossegue da seguinte forma:
|
|
|
|
1. Você navega até [https://example.com](https://example.com) e seleciona o botão “Integrar com Redes Sociais”.
|
|
2. O site então envia uma solicitação para [https://socialmedia.com](https://socialmedia.com) pedindo sua autorização para permitir que o aplicativo de https://example.com acesse suas postagens. A solicitação é estruturada como:
|
|
```
|
|
https://socialmedia.com/auth
|
|
?response_type=code
|
|
&client_id=example_clientId
|
|
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
|
|
&scope=readPosts
|
|
&state=randomString123
|
|
```
|
|
3. Você é então apresentado a uma página de consentimento.
|
|
4. Após sua aprovação, a Rede Social envia uma resposta para o `redirect_uri` com os parâmetros `code` e `state`:
|
|
```
|
|
https://example.com?code=uniqueCode123&state=randomString123
|
|
```
|
|
5. https://example.com utiliza este `code`, juntamente com seu `client_id` e `client_secret`, para fazer uma solicitação do lado do servidor para obter um `access_token` em seu nome, permitindo o acesso às permissões que você consentiu:
|
|
```
|
|
POST /oauth/access_token
|
|
Host: socialmedia.com
|
|
...{"client_id": "example_clientId", "client_secret": "example_clientSecret", "code": "uniqueCode123", "grant_type": "authorization_code"}
|
|
```
|
|
6. Finalmente, o processo conclui-se quando https://example.com utiliza seu `access_token` para fazer uma chamada de API para a Mídia Social para acessar
|
|
|
|
## Vulnerabilidades <a href="#id-323a" id="id-323a"></a>
|
|
|
|
### Open redirect\_uri <a href="#cc36" id="cc36"></a>
|
|
|
|
O `redirect_uri` é crucial para a segurança em implementações de OAuth e OpenID, pois direciona para onde dados sensíveis, como códigos de autorização, são enviados após a autorização. Se mal configurado, pode permitir que atacantes redirecionem essas solicitações para servidores maliciosos, possibilitando a tomada de conta.
|
|
|
|
As técnicas de exploração variam com base na lógica de validação do servidor de autorização. Elas podem variar desde correspondência estrita de caminho até aceitar qualquer URL dentro do domínio ou subdiretório especificado. Métodos comuns de exploração incluem redirecionamentos abertos, travessia de caminho, exploração de regex fracas e injeção de HTML para roubo de token.
|
|
|
|
Além do `redirect_uri`, outros parâmetros de OAuth e OpenID, como `client_uri`, `policy_uri`, `tos_uri` e `initiate_login_uri`, também são suscetíveis a ataques de redirecionamento. Esses parâmetros são opcionais e seu suporte varia entre os servidores.
|
|
|
|
Para aqueles que visam um servidor OpenID, o endpoint de descoberta (`**.well-known/openid-configuration**`) frequentemente lista detalhes de configuração valiosos, como `registration_endpoint`, `request_uri_parameter_supported` e "`require_request_uri_registration`. Esses detalhes podem ajudar a identificar o endpoint de registro e outras especificidades de configuração do servidor.
|
|
|
|
### XSS na implementação de redirecionamento <a href="#bda5" id="bda5"></a>
|
|
|
|
Como mencionado neste relatório de bug bounty [https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html](https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html), pode ser possível que a **URL de redirecionamento esteja sendo refletida na resposta** do servidor após o usuário se autenticar, sendo **vulnerável a XSS**. Payload possível para testar:
|
|
```
|
|
https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>
|
|
```
|
|
### CSRF - Manipulação inadequada do parâmetro de estado <a href="#bda5" id="bda5"></a>
|
|
|
|
Em implementações de OAuth, o uso indevido ou a omissão do **`state` parameter** pode aumentar significativamente o risco de ataques de **Cross-Site Request Forgery (CSRF)**. Essa vulnerabilidade surge quando o parâmetro `state` é **não utilizado, utilizado como um valor estático ou não validado corretamente**, permitindo que atacantes contornem as proteções contra CSRF.
|
|
|
|
Os atacantes podem explorar isso interceptando o processo de autorização para vincular sua conta à conta de uma vítima, levando a possíveis **account takeovers**. Isso é especialmente crítico em aplicações onde o OAuth é usado para **authentication purposes**.
|
|
|
|
Exemplos do mundo real dessa vulnerabilidade foram documentados em vários **CTF challenges** e **hacking platforms**, destacando suas implicações práticas. O problema também se estende a integrações com serviços de terceiros como **Slack**, **Stripe** e **PayPal**, onde os atacantes podem redirecionar notificações ou pagamentos para suas contas.
|
|
|
|
O manuseio e a validação adequados do **`state` parameter** são cruciais para proteger contra CSRF e garantir o fluxo do OAuth.
|
|
|
|
### Pre Account Takeover <a href="#ebe4" id="ebe4"></a>
|
|
|
|
1. **Sem Verificação de Email na Criação da Conta**: Os atacantes podem criar proativamente uma conta usando o email da vítima. Se a vítima usar um serviço de terceiros para login, a aplicação pode inadvertidamente vincular essa conta de terceiros à conta pré-criada do atacante, levando ao acesso não autorizado.
|
|
2. **Explorando a Verificação de Email Lax do OAuth**: Os atacantes podem explorar serviços de OAuth que não verificam emails registrando-se com seu serviço e, em seguida, alterando o email da conta para o da vítima. Esse método também arrisca o acesso não autorizado à conta, semelhante ao primeiro cenário, mas através de um vetor de ataque diferente.
|
|
|
|
### Divulgação de Segredos <a href="#e177" id="e177"></a>
|
|
|
|
Identificar e proteger parâmetros secretos do OAuth é crucial. Enquanto o **`client_id`** pode ser divulgado com segurança, revelar o **`client_secret`** apresenta riscos significativos. Se o `client_secret` for comprometido, os atacantes podem explorar a identidade e a confiança da aplicação para **roubar `access_tokens` de usuários** e informações privadas.
|
|
|
|
Uma vulnerabilidade comum surge quando as aplicações manipulam erroneamente a troca do `code` de autorização por um `access_token` no lado do cliente em vez do lado do servidor. Esse erro leva à exposição do `client_secret`, permitindo que os atacantes gerem `access_tokens` sob a aparência da aplicação. Além disso, através de engenharia social, os atacantes poderiam escalar privilégios adicionando escopos adicionais à autorização do OAuth, explorando ainda mais o status de confiança da aplicação.
|
|
|
|
### Client Secret Bruteforce
|
|
|
|
Você pode tentar **bruteforce o client\_secret** de um provedor de serviços com o provedor de identidade para tentar roubar contas.\
|
|
A solicitação para BF pode parecer semelhante a:
|
|
```
|
|
POST /token HTTP/1.1
|
|
content-type: application/x-www-form-urlencoded
|
|
host: 10.10.10.10:3000
|
|
content-length: 135
|
|
Connection: close
|
|
|
|
code=77515&redirect_uri=http%3A%2F%2F10.10.10.10%3A3000%2Fcallback&grant_type=authorization_code&client_id=public_client_id&client_secret=[bruteforce]
|
|
```
|
|
### Referer Header leaking Code + State
|
|
|
|
Uma vez que o cliente tenha o **code and state**, se estiver **refletido dentro do cabeçalho Referer** quando ele navega para uma página diferente, então está vulnerável.
|
|
|
|
### Access Token Stored in Browser History
|
|
|
|
Vá para o **histórico do navegador e verifique se o access token está salvo lá**.
|
|
|
|
### Everlasting Authorization Code
|
|
|
|
O **authorization code deve viver apenas por algum tempo para limitar a janela de tempo onde um atacante pode roubá-lo e usá-lo**.
|
|
|
|
### Authorization/Refresh Token not bound to client
|
|
|
|
Se você conseguir obter o **authorization code e usá-lo com um cliente diferente, então você pode assumir outras contas**.
|
|
|
|
### Happy Paths, XSS, Iframes & Post Messages to leak code & state values
|
|
|
|
[**Check this post**](https://labs.detectify.com/writeups/account-hijacking-using-dirty-dancing-in-sign-in-oauth-flows/#gadget-2-xss-on-sandbox-third-party-domain-that-gets-the-url)
|
|
|
|
### AWS Cognito <a href="#bda5" id="bda5"></a>
|
|
|
|
Neste relatório de bug bounty: [**https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/**](https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/) você pode ver que o **token** que **AWS Cognito** devolve ao usuário pode ter **permissões suficientes para sobrescrever os dados do usuário**. Portanto, se você puder **mudar o email do usuário para um email de usuário diferente**, pode ser capaz de **assumir** outras contas.
|
|
```bash
|
|
# Read info of the user
|
|
aws cognito-idp get-user --region us-east-1 --access-token eyJraWQiOiJPVj[...]
|
|
|
|
# Change email address
|
|
aws cognito-idp update-user-attributes --region us-east-1 --access-token eyJraWQ[...] --user-attributes Name=email,Value=imaginary@flickr.com
|
|
{
|
|
"CodeDeliveryDetailsList": [
|
|
{
|
|
"Destination": "i***@f***.com",
|
|
"DeliveryMedium": "EMAIL",
|
|
"AttributeName": "email"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
Para mais informações detalhadas sobre como abusar do AWS Cognito, consulte:
|
|
|
|
{% embed url="https://cloud.hacktricks.xyz/pentesting-cloud/aws-pentesting/aws-unauthenticated-enum-access/aws-cognito-unauthenticated-enum" %}
|
|
|
|
### Abusando de tokens de outros aplicativos <a href="#bda5" id="bda5"></a>
|
|
|
|
Como [**mencionado neste artigo**](https://salt.security/blog/oh-auth-abusing-oauth-to-take-over-millions-of-accounts), fluxos de OAuth que esperam receber o **token** (e não um código) podem ser vulneráveis se não verificarem se o token pertence ao aplicativo.
|
|
|
|
Isso ocorre porque um **atacante** poderia criar um **aplicativo que suporta OAuth e login com Facebook** (por exemplo) em seu próprio aplicativo. Então, uma vez que uma vítima faça login com Facebook no **aplicativo do atacante**, o atacante poderia obter o **token OAuth do usuário dado ao seu aplicativo e usá-lo para fazer login no aplicativo OAuth da vítima usando o token do usuário da vítima**.
|
|
|
|
{% hint style="danger" %}
|
|
Portanto, se o atacante conseguir fazer com que o usuário acesse seu próprio aplicativo OAuth, ele poderá assumir a conta da vítima em aplicativos que esperam um token e não verificam se o token foi concedido ao ID do seu aplicativo.
|
|
{% endhint %}
|
|
|
|
### Dois links & cookie <a href="#bda5" id="bda5"></a>
|
|
|
|
De acordo com [**este artigo**](https://medium.com/@metnew/why-electron-apps-cant-store-your-secrets-confidentially-inspect-option-a49950d6d51f), era possível fazer uma vítima abrir uma página com um **returnUrl** apontando para o host do atacante. Essa informação seria **armazenada em um cookie (RU)** e em um **passo posterior** o **prompt** **perguntaria** ao **usuário** se ele deseja conceder acesso ao host do atacante.
|
|
|
|
Para contornar esse prompt, era possível abrir uma aba para iniciar o **fluxo OAuth** que definiria esse cookie RU usando o **returnUrl**, fechar a aba antes que o prompt fosse exibido e abrir uma nova aba sem esse valor. Assim, o **prompt não informaria sobre o host do atacante**, mas o cookie seria definido para ele, então o **token seria enviado para o host do atacante** na redireção.
|
|
|
|
### Bypass de Interação do Prompt <a href="#bda5" id="bda5"></a>
|
|
|
|
Como explicado em [**este vídeo**](https://www.youtube.com/watch?v=n9x7_J_a_7Q), algumas implementações de OAuth permitem indicar o parâmetro **`prompt`** como None (**`&prompt=none`**) para **evitar que os usuários sejam solicitados a confirmar** o acesso concedido em um prompt na web se já estiverem logados na plataforma.
|
|
|
|
### response\_mode
|
|
|
|
Como [**explicado neste vídeo**](https://www.youtube.com/watch?v=n9x7_J_a_7Q), pode ser possível indicar o parâmetro **`response_mode`** para indicar onde você deseja que o código seja fornecido na URL final:
|
|
|
|
* `response_mode=query` -> O código é fornecido dentro de um parâmetro GET: `?code=2397rf3gu93f`
|
|
* `response_mode=fragment` -> O código é fornecido dentro do parâmetro de fragmento da URL `#code=2397rf3gu93f`
|
|
* `response_mode=form_post` -> O código é fornecido dentro de um formulário POST com um input chamado `code` e o valor
|
|
* `response_mode=web_message` -> O código é enviado em uma mensagem post: `window.opener.postMessage({"code": "asdasdasd...`
|
|
|
|
### Fluxo OAuth ROPC - bypass de 2 FA <a href="#b440" id="b440"></a>
|
|
|
|
De acordo com [**este post de blog**](https://cybxis.medium.com/a-bypass-on-gitlabs-login-email-verification-via-oauth-ropc-flow-e194242cad96), este é um fluxo OAuth que permite fazer login no OAuth via **nome de usuário** e **senha**. Se durante esse fluxo simples um **token** com acesso a todas as ações que o usuário pode realizar for retornado, então é possível contornar a 2FA usando esse token.
|
|
|
|
### ATO em redirecionamento de página da web baseado em redirecionamento aberto para referenciador <a href="#bda5" id="bda5"></a>
|
|
|
|
Este [**post de blog**](https://blog.voorivex.team/oauth-non-happy-path-to-ato) comenta como foi possível abusar de um **redirecionamento aberto** para o valor do **referenciador** para abusar do OAuth para ATO. O ataque foi:
|
|
|
|
1. A vítima acessa a página da web do atacante
|
|
2. A vítima abre o link malicioso e um opener inicia o fluxo OAuth do Google com `response_type=id_token,code&prompt=none` como parâmetros adicionais usando como **referenciador o site do atacante**.
|
|
3. No opener, após o provedor autorizar a vítima, ele os envia de volta para o valor do parâmetro `redirect_uri` (web da vítima) com código 30X que ainda mantém o site do atacante no referer.
|
|
4. O **site da vítima aciona o redirecionamento aberto baseado no referenciador**, redirecionando o usuário da vítima para o site do atacante, como o **`response_type`** era **`id_token,code`**, o código será enviado de volta ao atacante no **fragmento** da URL, permitindo que ele assuma a conta do usuário via Google no site da vítima.
|
|
|
|
### Parâmetros SSRFs <a href="#bda5" id="bda5"></a>
|
|
|
|
[**Verifique esta pesquisa**](https://portswigger.net/research/hidden-oauth-attack-vectors) **Para mais detalhes sobre esta técnica.**
|
|
|
|
O Registro Dinâmico de Clientes no OAuth serve como um vetor menos óbvio, mas crítico para vulnerabilidades de segurança, especificamente para ataques de **Server-Side Request Forgery (SSRF)**. Este endpoint permite que servidores OAuth recebam detalhes sobre aplicativos clientes, incluindo URLs sensíveis que podem ser exploradas.
|
|
|
|
**Pontos Chave:**
|
|
|
|
* **Registro Dinâmico de Clientes** é frequentemente mapeado para `/register` e aceita detalhes como `client_name`, `client_secret`, `redirect_uris` e URLs para logotipos ou Conjuntos de Chaves Web JSON (JWKs) via solicitações POST.
|
|
* Este recurso adere às especificações estabelecidas em **RFC7591** e **OpenID Connect Registration 1.0**, que incluem parâmetros potencialmente vulneráveis a SSRF.
|
|
* O processo de registro pode inadvertidamente expor servidores a SSRF de várias maneiras:
|
|
* **`logo_uri`**: Uma URL para o logotipo do aplicativo cliente que pode ser buscada pelo servidor, acionando SSRF ou levando a XSS se a URL for mal manipulada.
|
|
* **`jwks_uri`**: Uma URL para o documento JWK do cliente, que se for maliciosamente elaborado, pode fazer com que o servidor faça solicitações externas para um servidor controlado pelo atacante.
|
|
* **`sector_identifier_uri`**: Referencia um array JSON de `redirect_uris`, que o servidor pode buscar, criando uma oportunidade de SSRF.
|
|
* **`request_uris`**: Lista as URIs de solicitação permitidas para o cliente, que podem ser exploradas se o servidor buscar essas URIs no início do processo de autorização.
|
|
|
|
**Estratégia de Exploração:**
|
|
|
|
* SSRF pode ser acionado registrando um novo cliente com URLs maliciosas em parâmetros como `logo_uri`, `jwks_uri` ou `sector_identifier_uri`.
|
|
* Embora a exploração direta via `request_uris` possa ser mitigada por controles de lista branca, fornecer um `request_uri` pré-registrado e controlado pelo atacante pode facilitar SSRF durante a fase de autorização.
|
|
|
|
## Condições de Corrida dos provedores OAuth
|
|
|
|
Se a plataforma que você está testando é um provedor OAuth [**leia isso para testar possíveis Condições de Corrida**](race-condition.md).
|
|
|
|
## Referências
|
|
|
|
* [**https://medium.com/a-bugz-life/the-wondeful-world-of-oauth-bug-bounty-edition-af3073b354c1**](https://medium.com/a-bugz-life/the-wondeful-world-of-oauth-bug-bounty-edition-af3073b354c1)
|
|
* [**https://portswigger.net/research/hidden-oauth-attack-vectors**](https://portswigger.net/research/hidden-oauth-attack-vectors)
|
|
|
|
<figure><img src="https://pentest.eu/RENDER_WebSec_10fps_21sec_9MB_29042024.gif" alt=""><figcaption></figcaption></figure>
|
|
|
|
{% embed url="https://websec.nl/" %}
|
|
|
|
{% hint style="success" %}
|
|
Aprenda e pratique Hacking AWS:<img src="../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../.gitbook/assets/arte.png" alt="" data-size="line">\
|
|
Aprenda e pratique Hacking GCP: <img src="../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
|
|
|
<details>
|
|
|
|
<summary>Suporte ao HackTricks</summary>
|
|
|
|
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
|
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
|
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|
|
{% endhint %}
|