pwncat.channel package

Channels represent the basic communication object within pwncat. Each channel abstracts a communication method with a target. By default, pwncat implements a few standard channels: socket bind/connect and ssh.

A channel largely mimics a standard socket, however exact compatibility with sockets was not the goal. Instead, it provides a low-level communication channel between the target and the attacker. Channels make no assumption about protocol of the C2 connection. This is the platform’s job.

As a user, you will never directly create a channel. Instead, you will call pwncat.manager.Manager.create_session(). This method will in turn locate an appropriate channel based on your arguments, and pass all arguments to the constructor for the appropriate channel type.

class pwncat.channel.Channel(host: str, port: Optional[int] = None, user: Optional[str] = None, password: Optional[str] = None, **kwargs)

Bases: abc.ABC

Abstract interation with a remote victim. This class acts similarly to a socket object. In the common cases, it simply wraps a socket object. Some methods have default implementations, but many are required to be implemented. At a minimum, the following methods/properties must be implemented:

  • connected

  • send

  • recv

  • recvinto

  • drain

  • close

The peek and unrecv methods have default implementations which buffer some data in memory. If using the default implementations of these methods, you should be prepared to read first from self.peek_buffer prior to making downstream recv requests.

In general, direct connections are made during __init__. If you are implementing a listener, the connect method can be used to wait for/accept the final connection. It is called just before instantiating the resulting pwncat session. At all times, connected should reflect the state of the underlying data channel. In the case of listeners, connected should only be true after connect is called. The close method should set connected to false.

During initialization, you can take any keyword arguments you require to connect. However, you should also always accept a **kwargs argument. Parameters are passed dynamically from pwncat.channel.create and may be attempted with extra arguments you don’t need.

abstract close()

Close this channel. This method should do nothing if the connected property returns False.

connect()

Utilize the parameters provided at initialization to connect to the remote host. This is mainly used for channels which listen for a connection. In that case, __init__ creates the listener while connect actually establishes a connection. For direct connection-type channels, all logic can be implemented in the constructor.

This method is called when creating a platform around this channel to instantiate the session.

abstract property connected

Check if this channel is connected. This should return false prior to an established connection, and may return true prior to the connect method being called for some channel types.

drain()

Drain any buffered data until there is nothing left

makefile(mode: str, bufsize: int = - 1, sof: Optional[bytes] = None, eof: Optional[bytes] = None)

Create a file-like object which acts on this channel. If the mode is “r”, and sof and eof are specified, the file will return data following a line containing only sof and up to a line containing only eof. In “w” mode, the file has no bounds and will never hit eof.

Parameters
  • mode (str) – a mode string similar to open

  • sof (bytes) – a string of bytes which indicate the start of file

  • eof (bytes) – a string of bytes which indicate the end of file

Returns

A file-like object suitable for the specified mode

Return type

Union[BinaryIO, TextIO]

Raises

ValueError: both “r” and “w” were specified or invalid characters were found in mode

peek(count: Optional[int] = None, timeout: Optional[float] = None)

Receive data from the victim and leave the data in the recv buffer. This is a default implementation which uses an internal bytes buffer within the channel to simulate a peek. You can override this method if your underlying transport supports real peek operations. If the default peek implementation is used, recv should read self.peek_buffer prior to calling the underlying recv.

The timeout argument works differently from other methods. If no timeout is specified, then the method returns immediately and may return no data. If a timeout is provided, then the method will wait up to timeout seconds for at least one byte of data not to exceed count bytes.

Parameters

count (int) – maximum number of bytes to receive (default: unlimited)

Returns

data that was received

Return type

bytes

abstract recv(count: Optional[int] = None) bytes

Receive data from the remote shell

If your channel class does not implement peek, a default implementation is provided. If you provide a custom recv, but use the default peek() you must return data from self.peek_buffer prior to call recv.

Parameters

count (int) – maximum number of bytes to receive (default: unlimited)

Returns

the data that was received

Return type

bytes

recvinto(b)
recvline(timeout: Optional[float] = None) bytes

Receive data until a newline is received. The newline is not stripped. This is a default implementation that utilizes the recvuntil method.

Parameters

timeout (float) – a timeout in seconds for the recv

Return type

bytes

recvuntil(needle: bytes, timeout: Optional[float] = None) bytes

Receive data until the specified string of bytes is found is found. The needle is not stripped from the data. This is a default implementation which utilizes the recv method. You can override this if your underlying transport provides a better implementation.

Parameters
  • needle (bytes) – the bytes to wait for

  • timeout (Optional[float]) – a timeout in seconds (default: 30s)

Returns

the bytes that were read

Return type

bytes

abstract send(data: bytes)

Send data to the remote shell. This is a blocking call that only returns after all data is sent.

Parameters

data (bytes) – the data to send to the victim

Return type

None

sendline(data: bytes, end: bytes = b'\n')

Send data followed by an ending character. If no ending character is specified, a new line is used. This is a blocking call.

Parameters
  • data (bytes) – the data to send to the victim

  • end (bytes) – the bytes to append

Return type

None

unrecv(data: bytes)

Place the given bytes on a buffer to be returned next by recv. This method utilizes the internal peek buffer. Therefore, if you implement a custom peek method, you must also implement unrecv.

Parameters

data (bytes) – the data to place on the incoming buffer

Return type

None

exception pwncat.channel.ChannelClosed(ch)

Bases: pwncat.channel.ChannelError

A channel was closed unexpectedly during communication. This exception provides a cleanup() method which will cleanup the channel within the manager to ensure no further errors occur. This method is normally called by the manager itself upon catching the exception, but you should call this method if you intercept and do not re-throw the exception.

Parameters

ch (Channel) – the channel which caused the exception

cleanup(manager: pwncat.manager.Manager)

Cleanup this channel from the manager

exception pwncat.channel.ChannelError(ch, msg='generic channel failure')

Bases: Exception

Generic failure of a channel operation.

Parameters
  • ch (Channel) – the channel which caused the exception

  • msg (str) – a message describing the failure

class pwncat.channel.ChannelFile(channel: pwncat.channel.Channel, mode: str, sof: Optional[bytes] = None, eof: Optional[bytes] = None, on_close=None)

Bases: io.RawIOBase

Wrap a channel in a file-like object. Mainly used for process IO by the platform wrappers. It enables platforms to quickly create a file-like object which is bounded by a delimeter and can be returned to the user safely. You will not normally create this class directly, but should use the func:Channel.makefile` method instead.

Parameters
  • channel (Channel) – the channel to which we bind the file

  • mode (str) – a file mode (e.g. “r” or “w”)

  • sof (Optional[bytes]) – start of file delimeter; we will recv until this before returning.

  • eof (Optional[bytes]) – end of file delimeter; eof will be set after seeing this bytestr

  • on_close (Callable[[Channel], None]) – a method to call before closing the file

property blocking: bool

Indicates whether to act like a blocking file or not.

close()

Close the file for reading/writing. This method calls the on_close hook.

readable() bool

Test if this is a readable file.

readall()

Read all data until EOF

readinto(b: Union[memoryview, bytearray])

Read as much data as possible into the given bytearray or memory view.

Parameters

b (Union[memoryview, bytearray]) – the buffer data into

writable() bool

Test if this is writable file.

write(data: bytes)

Write the given data to the channel

Parameters

data (bytes) – the data to write to the channel

exception pwncat.channel.ChannelTimeout(ch, data: bytes)

Bases: pwncat.channel.ChannelError

A timeout was reached while reading or writing a channel.

Parameters

data (bytes) – the data read before the timeout occurred

pwncat.channel.create(protocol: Optional[str] = None, **kwargs) pwncat.channel.Channel

Create a new channel with the class provided by a registered channel protocol. Some assumptions are made if the protocol is not specified. For example, if no username or password are specified, then either bind or connect protocols are assumed. If a username is specified, the ssh protocol is assumed. In any case, with no protocol, a reconnect is attempted first.

Parameters

protocol (Optional[str]) – the name of the register channel protocol (e.g. ssh, bind, connect)

Returns

A newly connected channel

Return type

Channel

Raises
ChannelError: if the victim cannot be reached via the specified

protocol

pwncat.channel.find(name: str) Type[pwncat.channel.Channel]

Retrieve the channel class for the specified name.

Parameters

name (str) – the name of the channel you’d like

Returns

the channel class

Return type

Channel Class Object

pwncat.channel.register(name: str, channel_class: Type[pwncat.channel.Channel])

Register a new channel class with pwncat.

Parameters
  • name (str) – the name which this channel will be referenced by.

  • channel_class – A class object implementing the channel interface.