Ir para conteúdo

anderson_leite

Apoiador Nibble
  • Postagens

    29
  • Registro em

  • Última visita

  • Dias Ganhos

    8

Posts postados por anderson_leite

  1. 20 horas atrás, Pimptech disse:

    Compilou com GCC normal, nenhuma flag especial ? 
    Achei uma string bem peculiar nele.. 

    "ZN6Loader" E outras junções com esse "sufixo".. 

    Tudo normal, mas como está na descrição eu coloquei o RTTI para ajudar.

    Qualquer coisa entra la no discord, eu coloquei no canal Desafios e dai podemos bater um papo sobre alguma dúvida que não afete a resolução diretamente.

  2. Olá, trago mais um desafio interessante para Linux (logo logo atualizo com o binario para Windows também), onde você precisa montar a flag completa! Ao executar o binario ele vai te dar a metade da flag logo de cara, você deve ser capaz de entender como ele te mostrou essa flag inicialmente e também encontrar a outra metade!

    Está tudo liberado, você pode fazer patch, manipular o processo e etc... o importante aqui é entender como tudo funciona ?

     

    Algum tipo de proteção ? Não

    O Binário está stripped ? Sim, porém deixei o RTTI para facilitar

    Qual o formato ? ELF

     

     

    Regras:

    • Coloque  a tag de spoiler na sua resposta

    Algumas ferramentas que podem te ajudar a resolver:

    • x64dbg
    • IDA Free
    • Radare2
    • Cutter
    • GDB
    • Ghidra

    Divirta-se!

    inception

  3. Olá, trago mais um desafio interessante para Linux e Windows onde você só precisa acertar o seu valor de entrada para receber sua flag, a ideia aqui é treinar sua habilidade de analise de codigo e debugging para encontrar uma entrada que cause colisão.

    Algum tipo de proteção ? Não

    O Binário está stripped ? Não

    Qual o formato ? ELF & PE

    Regras:

    • Coloque  a tag de spoiler na sua resposta
    • Não será considerado uma solução valida se a mesma for baseada em patches
    • Não será considerado resoluções baseadas em brute force

     

    Algumas ferramentas que podem te ajudar a resolver:

    • x64dbg
    • IDA Free
    • Radare2
    • Cutter
    • GDB
    • Ghidra

     

    colide.exe colide

  4. Olá, mais um simples desafio para Linux e Windows onde você so precisa acertar o valor de entrada para receber seu parabéns ?

     

     

    Algum tipo de proteção ? Não

    O Binário está stripped ? Sim

    Qual o formato ? ELF & PE

     

    Regras:

    • Colocar tag de spoiler para sua resposta
    • Não será considerado uma solução valida se a mesma for baseada em patches
    • Não será considerado resoluções baseadas em brute force

     

    Algumas ferramentas que podem te ajudar a resolver:

    • x64dbg
    • IDA free
    • Radare2
    • Cutter
    • GDB
    • Ghidra

     

    Boa sorte ? 

    weaksum weaksum.exe

    • Curtir 1
  5. Olá, eis mais um simples desafio para Linux chamado revealme onde você precisa apenas precisa descobrir qual o comando este binário vai executar, porém para deixar o desafio mais interessante você deve realizar tudo usando apenas analise estática! ou seja, sem debugging! 

     

    Algum tipo de proteção ? Não

    O Binário está stripped ? Sim

    Qual o formato ? ELF

     

     

    Algumas ferramentas open source que podem te ajudar a resolver são:

    1.  Cutter
    2.  Radare
    3. Ghidra
    4. IDA Free

     

     

    Este desafio será usado no curso CR2 no canal do Papo binário, então caso não consiga basta assistir as aulas ?

    Boa sorte e divirta-se! 

     

    revealme

    • Curtir 1
    • l33t 1
  6. On 1/8/2022 at 9:47 PM, paulosgf said:

    Bom, isso foi uma análise feita a partir da força bruta, então teve um certo nível de ajuda para chegar na solução.

    Por acaso tu terias alguma estratégia de raciocínio que leve a solução sem força bruta?

    Abraços!

    Parabéns pela solução, e desculpa pela demora no feedback ? 

    Bom, vou deixar uma linha de raciocínio com a tag de spoiler:

     

    Spoiler

    Ao olhar o disassembling é possivel notar que o nosso input é usado como offset, ou seja, indice de um vetor. Você então pode tentar entender o que cada entrada faz com esse vetor e como eles são usados. Vale lembrar que vetores são apenas dados alinhados em memória pelo tamanho da variável usada. 

    Ao analisar isso, você provavelmente iria chegar em algum valor que tem referencia a uma função "oculta" dentro do binário, que não é chamada diretamente. 

    Talvez se você tivesse optado por uma analise estática usando o Cutter, radare ou o IDA isso teria ficado claro bem no inicio, pois essas tools descobrem funções espalhadas pelo binário. :

     

    • Curtir 1
    • l33t 1
  7. @paulosgfExcelente analise! O desafio é bem complicadinho mesmo mas a resolução é extremamente simples!, vou colocar minha dica na tag de spoilers

     

     

    Spoiler

    Toda a sua analise está correta até agora, o ponto chave para resolver agora é notar que sua entrada na vdd é um indice, veja que voce soma ela com um endereço e é dessa maneira que vetores são estruturados em memoria!

     

    Incrivel voce fazer tudo isso dentro do GDB! mas talvez se voce usasse o Cutter ou o Radare2, a analise estática já iria te revelar bastante coisa antes mesmo de entrar no debugger! Boa sorte

     

    Fico muito feliz que você esteja resolvendo.

    • Curtir 1
  8. Olá, decidi começar a publicar alguns desafios de engenharia reversa, criptografia e análise de malware nessa seção do forum!

    Para iniciar, eis um crackme para Linux chamado "Call me" onde você só precisa encontrar a chave correta e receber a sua mensagem de resolução ?

    Algumas considerações:

    • Coloque sua resolução com a tag de spoiler, para não mostrar para todos como resolveu
    • Resoluções por brute-force no input são validas, porém é sempre mais elegante entender o que está acontecendo por trás

     

    Dica: Caso sua "chave" esteja errada, você recebera um segmentation fault

    Algum tipo de proteção ? Não

    O Binário está stripped ? Sim

    Qual o formato ? ELF

    Algumas ferramentas open source que podem te ajudar a resolver são:

    1. Cutter
    2.  Radare
    3. gdb

     

    Boa sorte ?

    callme

  9. Excelente desafio, parabéns pelo packer! por mais simples que seja rende um bom aprendizado.

    Segue minha resolução abaixo, se as imagens ficarem pequenas pode clicar que expande.

     

    Spoiler

    1 - Overview

    Sabendo que estamos trabalhando diretamente com um packer,  podemos primeiro dar uma olhadas nas seções na esperança de já encontrar aonde vai estar o código "packeado" e unpacked:

    overview seções

    A visão acima, no Cutter , revela algumas informações interessantes:

    1. 2 seções com nomes incomums: .wohami e .hakuoo
    2.  O tamanho em disco da .wohami sendo 0 e seu tamanho virtual sendo 0x2000
    3. Entropia presente na seção .hakuoo sendo bem elevado, o que indica algum tipo de compressão ou criptografia
    4. Permissões de escrita, leitura e execução em ambas

    Todos os fatos indicam que de fato é um packer, e que provavlmente o código unpacked será copiado para a seção .wohami, também podemos inferir que modificações serão feitas na seção .hakuoo,  por conta da permissão de escrita.

    2 - Rika packer - Manual unpack e reconstrução da IAT

    A maioria dos packers  seguem a seguinte ordem de execução:

    1. Carregamento de informações basicas como: ImageBase, OEP, IAT address
    2. Descompressão/decriptografia do código packeado
    3. Reconstrução da IAT
    4. jump para OEP

    Com o Rika não é diferente, logo no inicio já vemos uma chamada a função que vai realizar o unpack  que recebe um argumento que aponta para o inicio da seção .hakuoo, onde será extraido os dados necessários para iniciar o unpack:

    entrypoint

     

    Note também, que logo após a call para o unpack, é feio um jump para o valor retornado, dword ptr [ebp-4] que recebe o valor de eax (retorno da função), este é o nosso OEP, mas irei explicar o motivo disso porém essa informação de antemão (pela estrutura) é importante para que seja possível reconstruir, mesmo que parcialmente, a header desse packer.

     

    Primeiro acessos a header

     

    No inicio da função, podemos notar que existe acessos ao endereço que foi passado como argumento (eu renomeiei para rikaHdr), note também que existem varios outros acessos a offsets especificos como ecx+8, ecx+2C, ecx+18 e etc. Isso nada mais é que o acesso a um elemento de uma struct,  já que structs são apenas dados alinhados em memória e não existem de fato quando o código é compilado, para facilitar podemos reconstruir as structs com o IDA, porém antes de realizar isso, abrindo o desafio no x32dbg e colocando um breakpoint nos endereços que realizam acesso ao offset 0x18 da header, 0x407BA4F, é possível notar que está sendo carregado os endereços das funções importadas:

    importsLoading.thumb.png.b2094d366714df92c1a5a8896d3ec1be.png

     

    Então podemos deduzir que no offset 18 é guardado o endereço da LoadLibraryA, porém nos próximos valores também são guardados os endereços das funções VirtualAlloc, VirtualFree e GetProcAddress, em sequência na memória o que é possível deduzir que estão em um vetor de ponteiros.

    Bom, o processo inteiro de reconstruir structs é bem complicado e requer bastante atenção então para não perder muito tempo, irei colocar a struct na qual eu reconstrui e que foi usado para obtenção do OEP e da rotina que realiza a reconstrução da IAT:

     

    struct rikaHdr {
        DWORD* imageBase;
        DWORD  OEPRVA;
        DWORD  numChunks; // Primeiro imaginei que fosse o numero de imports, porém casa melhor o número de "partes" que foram comprimidas
        DWORD  IATRVA;
        DWORD  packedSize;
        DWORD  unpackedSize;
        DWORD  unknown_1;
        DWORD** importAddrs;
        DWORD  unknown_2;
        DWORD  dstSecRVA; // RVA para a seção wohami
    };

    Após construir essa struct no IDA, fruto de uma analise mais minuciosa e muito passível de erro, o código tanto do  decompiler quanto do disassembler fica mais simples de se ler:

    Struct da header parcialmente reconstruida

    Claro, existe outras structs aqui como visto na variavel packedHdr que ocorre logo após a rikaHdr, porém não tomei muito esforço para reconstruir visto que só com a rikaHdr é possível encontrar o OEP e reconstruir a IAT.

     

    A estrutura do unpack adotado no rika tem os seguintes passos:

    • É criado um primeiro buffer que irá guardar valores parciais da descompressão
    • São criado então mais 2 buffers que irão ser usados de maneiras complementares ao primeiro para descompressão total
    •  É então criado um buffer para salvar todo o código unpacked
    •  Logo em seguido é copiado byte a byte para seção .wohami
    • A IAT é então reconstruida
    • Retorna então a soma da imageBase com o RVA do OEP

    Os passos podem ser vistos na seguinte visão do decompiler, para fácil entendimento:

    unpackedData.thumb.png.8648448a542b977d9065cac7ae1556b9.png

    Então é copiado byte a byte até a seção que irá salvar o código descomprimido, o mesmo pode ser visto também no x32dbg:

     

    whoamicopy.thumb.png.17808ef53466609b4c1e3cbdc18e5e35.png

     

    É possível também confirmar que este endereço 0x401000 é o endereço que inicia a seção olhando no memory map:

    image.thumb.png.fd596e446eaea3bb762704193824a808.png

    Após isto, a IAT é reconstruida usando o RVA da iat, salvo na rikaHdr para encontrar cada endereço, carregar a biblioteca necessario e então preencher a com o endereço de cada função importada:

    IATRebuild.thumb.png.0758d74d0bd0d7e8859dd94d3e4a8080.png

    Após esse processo ser terminado, a função então termina retornando a soma da imageBase com  o RVA do OEP, que também são elementos da rikaHdr

     

    returnOEP.thumb.png.16261a47082eca13e170f1cc70333386.png

     

    Agora sabendo disso tudo, podemos proceder para o nosso própio manual unpack dentro do x32dbg, podemos deixar toda a rótina de descompressão ocorrer até o jump para o OEP e então realiza o dump do PE e reconstruir a IAT usando o Scylla.

    Também visto na imagem acima, é possivel fazer o calculo manual do valor do OEPRVA e da imageBase para encontrar o OEP, que fica em 0x4019FF, então basta por um breakpoint nesse endereço e esperar chegar nele ?

    unpackAndIATRebuild.thumb.png.5a9f0a8ab1466c149df30a0bf3a72dbd.png

    Excelente, manual unpack feito e IAT reconstruida, agora sim podemos passar para o reverse me!

    3 - Reverse me

    O desafio em si é simples, apenas encontre a chave/entrada correta que levará até a mensagem "Successo :)", porém o nosso amigo @Hakuooadicionou algumas técnicas de Anti-VM e Anti-Debugging para dificultar nossa vida, então vamos resolver tudo isso.

     

    ba900cbf08abfa2e4be892275b425619.thumb.png.1594e1ed9c847807581f8ba91b436490.png

     

    Logo no inicio já temos uma técnica de Anti-Debugging usando a instruçã  rdtsc, Read Time-Stamp Counter, que é usada para contar quantos ciclos da CPU ocorreu desde da ultima instrução, esses valores são checados varias vezes, o que em si atrapalha a gente quando estamos realizando o debugging por step-by-step, mas não tem muita influência caso a gente só passe por cima delas, então por um breakpoint logo após a segunda chamada é uma maneira de burlar isso, mas vale lembrar que em algumas situações o nosso "tick" pode ser maior que o checado mesmo dando um "continue" no debugger então é bom ficar atento a isso também.

    Não só isso é usado, como também, caso o rdtsc falhe, será chamada uma função na qual renomeiei para cpuid_trick:

     

    cpu_trick.thumb.png.405fd415a7322dc203c3a7eb27b3de85.png

     

    Onde principalmente é chamado a instrução cpuid com o valor de EAX igual a 1, para obter as features implementadas na CPU e com isso caso o valor diferente de 0 é possível detectar se estamos dentro de um ambiente virtualizado, visto que este valor seria preenchido por 1 dentro de um hypervisor, nossa VM. Sendo somente uma função, é possível apenas fazer um patch inline para sempre retornar 0 em eax, existe uma maneira tbm de editar os arquivos de configuração da nossa VM para fazer com que sempre retorne 0, porém para manter a simplicidade um patch para debugging funciona bem, e quando for executar apenas definir para nossa VM retornar 0.

    patcheax.thumb.png.a51e0abfcfa422f7dde73a2ea37d52ba.png

     

    Ainda é feito uma chamada para a função IsDebuggerPresent, porém por default o x32dbg salva como falso o valor usado IsDebuggerPresent na PEB. Assim com o patch na função que checa as informações da CPU e pulando as calls para a instrução rdtsc, evitamos todas as detecções de que estamos realizando debugging ou rodamos dentro de uma VM!

    Bom, eventualmente, nosso input é jogado para ser validado numa função em 0x401050, onde é checado se a nossa entrada multiplicada por 0xd93f5 é igual a 0x15682B45C343B

    checagemInput.thumb.png.cc96022ea9bc2fdff8ac684a925b8f35.png

     

    Vale notar dois pontos aqui:

    • Nosso registrador de 32 bits não consegue guardar um valor desse tamanho, então na instrução real é feito a checagem em 2 partes enquanto no decompiler temos uma visão high level
    • Para realizar a multiplição é usado a rotina allmul que é  preenchida pelo compilador para realizar calculos de maiores magnitudes

     

    É facil então encontrar a entrada correta, basta dividir  0x15682B45C343B por 0xd93f5  que é igual a 0x1939b96f, ou 423213423.

    No meu caso, no binario feito o unpack, eu precisei também fazer um patch na função de multiplicação e divisão para que fosse enviado os valores corretos, visto que após o unpack alguns valores na stack ficaram provavelmente desalinhados e o meu PE estava realizando a multiplicação pelo endereço da LoadLibraryA, porém no binario original isso não ocorre.

    Logo após a primeira checagem, é aplicado novamente as técnicas de anti-vm e anti-debugging:

    antischeck.thumb.png.e59f3ff1548326c62e6f1eb2228caea0.png

    Mas, facilmente "bypassavel" pelo patch que foi feito e por passar direto na contagem de ciclos.

    Nossa entrada novamente é checada pela divisão pelo valor 0x2E9 (745) e enviado para a função alldiv que tem o mesmo proposito da allmul, porém para realizar a divisão, é feito as mesmas checagens de anti-vm e anti-debugging, então é verificado se o resultado da divisão é igual a 568071:

    alldiv.thumb.png.df440d18f28eb311949a51871446d4e5.png

    O valor 423213423 casa certinho para essa divisão também, considerando apenas a parte inteira do resultado da divisão. Logo após isso nossa entrada é somada com o valor 4444 e então, retornada. O valor é validado algumas instruções seguintes para que seja possível dar continuidade a execução:

    keyCheck.thumb.png.d89a35c5fab3f96b3fd0651996139310.png

     

    Lembrando que nossa chave é dividida e somada com 4444 o que resulta em 0x8bc63, com isso é então chamada a ultima função que realiza o print na tela de "Sucesso :)"!

    sucesso.thumb.png.8490d2ef7622c915046ca64e3dca9c33.png

     

    É isso, se tiver qualquer equivoco ou erro pode avisar, e o quão perto eu cheguei na reconstrução da struct ? hahaha

     

     

    Também, meu feedback sobre o packer abaixo:

     

    Spoiler

    Não sou nenhum especialista em desenvolvimento de packers, porém esse tem uma estrutura bem comum com os demais que tem apenas o papel de comprimir/diminuir o tamanho do executável, então minhas dicas para deixar mais difícil de fazer o manual unpack ou eng reversa seria:

    • Esconder o OEP junto com os dados comprimidos e não deixar ele na header, do jeito que tava ficava fácil sempre achar o OEP
    • Quebrar o unpack em partes, uma função para fazer apenas o unpack e seguido de um jump/call para reconstruir a IAT
    • O carregamento das funções pode também ser feito usando o PEB_LDR_DATA  dentro da PEB
    • Não copiar o valor para outra seção, tenta reescrever na seção do .hakuoo mesmo

    Bom, contando que é apenas um packer e não um protector ou crypter, acho que essas mudanças são boas para deixar ele mais difícil de ser reconhecido e de ser feito o unpack de maneira comum.

     

     

     

    • Curtir 1
    • l33t 1
×
×
  • Criar Novo...