[ Inicio ] [ Hacking ] [ CTFs ] [ Rant ]
.:: Brenn0 Weblog ::.

Título : Escondendo strings e dificultando a análise de um binário [Parte 1]
Autor : brennords
Data : 20/06/2017
            

Em um belo e aleatório dia, resolvi que iria criar desafios para um CTF inexistente. Sem grandes pretensões. Tinha apenas a intenção de aprender como resolver os desafios criados por outros seres, já que tentar recriar os mecanismos de segurança que se quer burlar pode ser uma ótima forma de aprender a alcançar tal feito.

Meu objetivo inicial foi criar um leve binário no linux que recebesse uma senha como entrada e, se a senha estivesse correta, imprimisse a flag.

O primeiro código que escrevi foi esse:

Bem simples, não?

Ao compilar e rodar, tudo funcionou como deveria:

brenno@budweiser:~/Docs/ctf/brenn0$ gcc chall_versao0.c -o chall_versao0
brenno@budweiser:~/Docs/ctf/brenn0$ ./chall_versao0
Uso: ./chall_versao0 [senha]
brenno@budweiser:~/Docs/ctf/brenn0$ ./chall_versao0 123
Sai daqui, porra!
brenno@budweiser:~/Docs/ctf/brenn0$ ./chall_versao0 bbb
Sai daqui, porra!
brenno@budweiser:~/Docs/ctf/brenn0$ ./chall_versao0 666
Tome sua flag: CTF{UAL}

A intenção aqui é fazer com que o ser faça a engenharia reversa do binário, abra o gdb, sete uns breakpoints, descubra o valor da senha ou até simplesmente faça um jmp safado e imprima a flag na tela.

Mas sabemos como esses hackudos são. Imaginei que a primeira coisa que fariam seria usar o comando strings em cima do meu binário na busca de uma flag fácil.

brenno@budweiser:~/Docs/ctf/brenn0$ strings chall_versao0
/lib64/ld-linux-x86-64.so.2
libc.so.6
puts
__stack_chk_fail
printf
atoi
__libc_start_main
__gmon_start__
GLIBC_2.4
GLIBC_2.2.5
UH-P
CTF{UAL}H
AWAVA
AUATL
[]A\A]A^A_
Uso: %s [senha]
Tome sua flag: %s
Sai daqui, porra!
;*3$
GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
crtstuff.c
__JCR_LIST__
deregister_tm_clones
__do_global_dtors_aux
[...]

E a flag está mesmo disponível de forma fácil. Os que são ainda mais hackers poderiam, caso conhecessem o formato da flag, fazer apenas:

brenno@budweiser:~/Docs/ctf/brenn0$ strings chall_versao0 | grep CTF
CTF{UAL}H

Não escrevi 24 linhas de código para ver meu chall resolvido em 2 segundos. Isso fez com que eu fosse em busca de formas para esconder melhor a string. Queria algo simples e facilmente quebrável. Logo, ignorei as sugestões de usar criptografia e outros métodos mais 1337 que eu.

Após algumas pesquisas, descobri que o comando string, usado cru, sem opcionais, busca no binário apenas strings maiores que 3. Ou seja, modificando meu código atual para partir a flag em pedaços poderia esconde-la melhor.

Agora ao compilar e passar o strings o resultado era esse:

brenno@budweiser:~/Docs/ctf/brenn0$ gcc chall_versao1.c -o chall_versao1
brenno@budweiser:~/Docs/ctf/brenn0$ strings chall_versao1
[...]
UH-P
AWAVA
AUATL
[]A\A]A^A_
Uso: %s [senha]
Tome sua flag: %s%s%s%s
Sai daqui, porra!
;*3$
GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
crtstuff.c
__JCR_LIST__
deregister_tm_clones
[...]

Sem flag via strings!

Mas depois de ter estudado o strings, me liguei que o hackudo mais hackudão dominador do comando poderia tentar usar sua funcionalidade de forma estendida. Era só passar como argumento -n 2 que o comando iria retornar strings maiores que 1.

brenno@budweiser:~/Docs/ctf/brenn0$ strings -n2 chall_versao1
ELF
td
[lixo pra caralho]
UH
UH
UH
dH
%(
CT
F{
UA
L}
H
TH
;E
u'H
dH3
%(
f.
AWAVA
AUATL
UH
SI
L)
t 1
H9
[]A\A]A^A_
f.
Uso: %s [senha]
Tome sua flag: %s%s%s%s
Sai daqui, porra!
;4
zR
[mais lixo pra caralho]
completed.7585

Tem bem mais porcaria no resultado. Mesmo assim, como nunca deve se duvidar de um hackudo motivado, a flag, mesmo repartida, está visível nas linhas destacadas.

E agora?

Claro que poderia partir a flag caracter por caracter, mas decidi inserir outros caracteres em meio a flag real para confundir (até disfarça a flag no disas de main, no próximo post falo mais sobre) e tentar obrigar o ser a resolver o desafio do jeito que pretendi.

O código ficou assim:

Ao compilar e tentar pescar algo com strings -n2 teremos:

brenno@budweiser:~/Docs/ctf/brenn0$ gcc chall_versao2.c -o chall_versao2
brenno@budweiser:~/Docs/ctf/brenn0$ strings -n2 chall_versao2
ELF
[lixo lixo lixo]
UH
dH
%(
CT
TC
F{
{F
UA
AU
L}
}L
#H
`H
u'H
dH3
%(
AWAVA
AUATL
UH
SI
L)
t 1
H9
[]A\A]A^A_
f.
Uso: %s [senha]
Tome sua flag: %s%s%s%s
Sai daqui, porra!
;4
zR
zR
;*3$
@r
[lixo lixo lixo]

Ela continua surgindo, mas é bem mais difícil de reconhece-la. E agora acredito que seja menos custoso tentar traduzi-la nesse meio ao invés de abrir o debugger e começar a hackinagem de verdade.

Esta postagem está se tornando grande demais e, com base nos padrões atuais de leitura e engajamento do usuário médio da world wide web, preciso finaliza-la para evitar problemas de monetização. Deixo para contar em uma eventual segunda parte as técnicas que usei para criar uma versão melhorada desse desafio. Usei umas noobices legais anti-debugging e expandi o aprendizado. Siga-me e tenha a garantia que não irá perder o próximo post.

E usando essa desculpa cheia de palavras bonitas para justificar a preguiça, finalizo esta linda e glamorosa postagem de técnicas 1337.

Antes que esqueça, aqui vão uns links que me ajudaram a aprender: