From a600075abf8515977c7728b35e8677d7d5f1756c Mon Sep 17 00:00:00 2001 From: "Tyler St. Onge" Date: Sat, 22 Aug 2020 01:53:25 -0400 Subject: ability to accept files over passive connection --- .../tylerstonge/honeypot/ftp/FtpFileReceiver.scala | 27 ++++++++---- .../honeypot/ftp/FtpFileRetriever.scala | 50 ---------------------- .../com/tylerstonge/honeypot/ftp/FtpHandler.scala | 32 +++++++------- .../com/tylerstonge/honeypot/ftp/FtpListener.scala | 2 +- 4 files changed, 37 insertions(+), 74 deletions(-) delete mode 100644 src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileRetriever.scala diff --git a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileReceiver.scala b/src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileReceiver.scala index 74ca594..9f88b06 100644 --- a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileReceiver.scala +++ b/src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileReceiver.scala @@ -1,9 +1,11 @@ package com.tylerstonge.honeypot.ftp +import java.io.File import java.net.InetSocketAddress -import java.nio.file.{Files, OpenOption, Paths, StandardOpenOption} +import java.nio.file.{Files, Paths, StandardOpenOption} +import java.util.UUID -import akka.actor.{Actor, Props} +import akka.actor.{Actor, ActorRef, Props} import akka.event.{Logging, LoggingAdapter} import akka.io.Tcp._ import akka.io.{IO, Tcp} @@ -11,30 +13,39 @@ import akka.util.{ByteString, ByteStringBuilder} object FtpFileReceiver { - def props(port: Int): Props = Props(new FtpFileReceiver(port)) + def props(port: Int, controller: ActorRef): Props = Props(new FtpFileReceiver(port, controller)) } -class FtpFileReceiver(port: Int) extends Actor { +class FtpFileReceiver(port: Int, controller: ActorRef) extends Actor { val log: LoggingAdapter = Logging(context.system, this) - IO(Tcp)(context.system) ! Bind(self, new InetSocketAddress("localhost", port)) + IO(Tcp)(context.system) ! Bind(self, new InetSocketAddress("127.0.0.1", port)) val fileData: ByteStringBuilder = ByteString.newBuilder + val name: String = UUID.randomUUID().toString + + override def postStop { + log.debug("shutting down") + } override def receive: Receive = { case Bound(localAddress) => log.info("listening on {}", localAddress) case CommandFailed(_: Bind) => context.stop(self) case Connected(_, _) => - log.info("peer connected") + val connection = sender() + connection ! Register(self) context.become { case Received(data) => + log.info("read {} bytes", data.length) fileData.addAll(data) case PeerClosed => - log.info("peer closed connection, writing file to disk") - val out = Files.newByteChannel(Paths.get("testfile.txt"), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE) + log.debug("peer closed connection, writing file to disk") + val out = Files.newByteChannel(new File("C:\\Users\\dropkick\\Documents\\dev\\honeypot\\" + this.name).toPath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE) out.write(fileData.result().toByteBuffer) out.close() + controller.tell(Write(ByteString.apply("226 File transferred.\n")), context.parent) context.stop(self) + case msg@_ => log.warning("unknown message: {}", msg) } } } diff --git a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileRetriever.scala b/src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileRetriever.scala deleted file mode 100644 index 1e441dd..0000000 --- a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpFileRetriever.scala +++ /dev/null @@ -1,50 +0,0 @@ -package com.tylerstonge.honeypot.ftp - -import java.net.InetSocketAddress -import java.nio.file.{Files, Paths} - -import akka.actor.{Actor, Props} -import akka.event.{Logging, LoggingAdapter} -import akka.io.Tcp._ -import akka.io.{IO, Tcp} -import akka.util.{ByteString, ByteStringBuilder} - -object FtpFileRetriever { - def props(remote: InetSocketAddress): Props = Props(new FtpFileRetriever(remote)) -} - -class FtpFileRetriever(remote: InetSocketAddress) extends Actor { - - val log: LoggingAdapter = Logging(context.system, this) - IO(Tcp)(context.system) ! Connect(remote) - val fileData: ByteStringBuilder = ByteString.newBuilder - - override def preStart(): Unit = { - super.preStart() - log.info("started retrieving from {}:{}", remote.getHostString, remote.getPort) - } - - override def receive: Receive = { - case CommandFailed(_: Connect) => - context.stop(self) - case c@Connected(_, _) => - val connection = sender() - connection ! Register(self) - context.become { - case data: ByteString => - log.info("received {} bytes", data.length) - fileData.addAll(data) - case CommandFailed(w: Write) => - log.info("command failed") - case Received(data) => - log.info("received {} bytes", data.length) - fileData.addAll(data) - case _: ConnectionClosed => - log.info("peer closed connection, writing file to disk") - val out = Files.newByteChannel(Paths.get("testfile.txt")) - out.write(fileData.result().toByteBuffer) - out.close() - context.stop(self) - } - } -} diff --git a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpHandler.scala b/src/main/scala/com/tylerstonge/honeypot/ftp/FtpHandler.scala index 8bdb190..840ce97 100644 --- a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpHandler.scala +++ b/src/main/scala/com/tylerstonge/honeypot/ftp/FtpHandler.scala @@ -1,18 +1,20 @@ package com.tylerstonge.honeypot.ftp -import java.net.InetSocketAddress - -import akka.actor.Actor +import akka.actor.{Actor, ActorRef, Props} import akka.event.{Logging, LoggingAdapter} import akka.io.Tcp.{PeerClosed, Received, Write} import akka.util.ByteString -class FtpHandler extends Actor { +object FtpHandler { + def props(client: ActorRef): Props = Props(new FtpHandler(client)) +} + +class FtpHandler(client: ActorRef) extends Actor { val log: LoggingAdapter = Logging(context.system, this) override def receive: Receive = { - case Received(data) => sender() ! Write(ByteString.apply(parse(sanitize(data)))) + case Received(data) => client ! Write(ByteString.apply(parse(sanitize(data)))) case PeerClosed => log.info("peer closed connection") context.stop(self) @@ -28,18 +30,22 @@ class FtpHandler extends Actor { case "pwd" => "257 \"/\" is the current directory\n" case "quit" => "221 Goodbye.\n" case "pasv" => - context.actorOf(FtpFileReceiver.props(1287)) + log.info("entering passive mode") + context.actorOf(FtpFileReceiver.props(1287, client), name = "passive-connection") + Thread.sleep(256) "227 entering passive mode (127,0,0,1,5,7)\n" - case "port" => - context.actorOf(FtpFileRetriever.props(new InetSocketAddress(getHostname(msg(1)), getPort(msg(1))))) - "200 OK\n" case "stor" => - "200 OK \n" + log.info("stor: {}", msg(1)) + "150 File status okay; about to open data connection.\n" case _ => log.info("unsupported command received: {}", msg.mkString(" ")) "451 Requested action aborted. Local error in processing.\n" } + def sanitize(data: ByteString): Array[String] = { + data.utf8String.trim.toLowerCase().split(" ") + } + def getHostname(msg: String): String = { val split = msg.split(",") split.slice(0, 4).mkString(".") @@ -49,8 +55,4 @@ class FtpHandler extends Actor { val split = msg.split(",") split(4).toInt * 256 + split(5).toInt } - - def sanitize(data: ByteString): Array[String] = { - data.utf8String.trim.toLowerCase().split(" ") - } -} +} \ No newline at end of file diff --git a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpListener.scala b/src/main/scala/com/tylerstonge/honeypot/ftp/FtpListener.scala index 07557bc..b7ce337 100644 --- a/src/main/scala/com/tylerstonge/honeypot/ftp/FtpListener.scala +++ b/src/main/scala/com/tylerstonge/honeypot/ftp/FtpListener.scala @@ -22,8 +22,8 @@ class FtpListener(port: Int) extends Actor { log.info("listening on {}", localAddress) case CommandFailed(_: Bind) => context.stop(self) case Connected(_, _) => - val handler = context.actorOf(Props[FtpHandler]) val connection = sender() + val handler = context.actorOf(FtpHandler.props(connection), name = "handler") connection ! Register(handler) connection ! Write(ByteString.apply("220 (vulnFTPd 2.0.1)\n")) } -- cgit v1.1