This content originally appeared on DEV Community and was authored by Piotr Zarycki
Bash has a hidden capability to make HTTP requests without needing tools like curl or wget. Let’s explore how this works.
First, let’s check the bash man page:
man bash
In the REDIRECTION section, you’ll find an interesting detail:
Bash handles several filenames specially when they are used in redirections. If the operating system on which Bash is running provides these special files, Bash will use them; otherwise, it will emulate them internally with the behavior described below.
Bash handles several filenames specially when they are used in redirections, as described in the following table. If the operating system on which bash is running provides these
special files, bash will use them; otherwise it will emulate them internally with the behavior described below.
/dev/fd/fd
If fd is a valid integer, file descriptor fd is duplicated.
/dev/stdin
File descriptor 0 is duplicated.
/dev/stdout
File descriptor 1 is duplicated.
/dev/stderr
File descriptor 2 is duplicated.
/dev/tcp/host/port
If host is a valid hostname or Internet address, and port is an integer port number or service name, bash attempts to open the corresponding TCP socket.
/dev/udp/host/port
If host is a valid hostname or Internet address, and port is an integer port number or service name, bash attempts to open the corresponding UDP socket.
If you try to list the /dev/tcp
directory, you’ll get the following error:
ls -lat /dev/tcp
/dev/tcp: No such file or directory (os error 2).
This is because /dev/tcp
is not an actual path on the filesystem; it’s a feature of Bash itself, not the underlying Linux system.
To use this feature, you need to call it as part of the Bash execution environment using the exec command:
exec 3<>/dev/tcp/example.org/80
We’ll discuss the 3<>
syntax later. After running this command, it may seem like nothing happens, but there’s more going on behind the scenes.
Let’s use strace
to investigate further. Among the output, the most interesting part is:
.......
close(3) = 0
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.184.215.14")}, 16) = 0
This confirms that the exec command created a TCP/IP socket bound to example.org
.
In Linux, everything is treated as a file, including network connections, which are represented as “files” called file descriptors. You can list all file descriptors for the current process by checking the /proc/self/fd/
directory:
ls -lat /proc/self/fd/
lrwx------ 1 piotr piotr 64 Aug 25 15:01 0 -> /dev/pts/0
lrwx------ 1 piotr piotr 64 Aug 25 15:01 1 -> /dev/pts/1
lrwx------ 1 piotr piotr 64 Aug 25 15:01 2 -> /dev/pts/2
lrwx------ 1 piotr piotr 64 Aug 25 15:01 3 -> 'socket:[2910856]'
lr-x------ 1 piotr piotr 64 Aug 25 15:01 4 -> /proc/1579316/fd
Here, 3
is the file descriptor for the socket connected to example.org
. The exec 3<> /dev/tcp/...
syntax essentially means:
"create a socket for input and output operations with file descriptor with process identifier equals 3."
Next, let’s send a GET request:
echo -ne "GET / HTTP/1.1\r\nHost: example.org\r\n\r\n" >&3
Although it may appear that nothing happens, you’ve just sent data through the socket.
To read the response, use:
cat <&3
HTTP/1.1 200 OK
Age: 243157
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Sun, 25 Aug 2024 14:15:54 GMT
Etag: "3147526947+ident"
Expires: Sun, 01 Sep 2024 14:15:54 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECAcc (dcd/7D77)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
......................REST............
You’ve successfully downloaded a webpage! Afterward, remember to close the socket:
exec 3<&-
You might wonder why this feature exists.
Originally, it was copied from the KornShell (ksh) to open network connections and assign them to file descriptors
It was intended to send data across networks, such as for generating reports.
This feature can also be exploited to create reverse shells by hackers or penetration testers.
This content originally appeared on DEV Community and was authored by Piotr Zarycki
Piotr Zarycki | Sciencx (2024-08-26T16:36:08+00:00) How to make http request without curl or wget in bash. Retrieved from https://www.scien.cx/2024/08/26/how-to-make-http-request-without-curl-or-wget-in-bash/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.